Overview
GLMR Balance
GLMR Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 4158541 | 903 days ago | 0 GLMR | ||||
| 4158541 | 903 days ago | 0 GLMR | ||||
| 4158541 | 903 days ago | 0 GLMR | ||||
| 4158541 | 903 days ago | 0 GLMR | ||||
| 4133772 | 906 days ago | 0 GLMR | ||||
| 4131676 | 907 days ago | 0 GLMR | ||||
| 4128492 | 907 days ago | 0 GLMR | ||||
| 4128492 | 907 days ago | 0 GLMR | ||||
| 4128492 | 907 days ago | 0 GLMR | ||||
| 4128492 | 907 days ago | 0 GLMR | ||||
| 4128492 | 907 days ago | 0 GLMR | ||||
| 4128492 | 907 days ago | 0 GLMR | ||||
| 4010740 | 924 days ago | 0 GLMR | ||||
| 4006918 | 924 days ago | 0 GLMR | ||||
| 4006908 | 924 days ago | 0 GLMR | ||||
| 4006872 | 924 days ago | 0 GLMR | ||||
| 4006847 | 924 days ago | 0 GLMR | ||||
| 4002251 | 925 days ago | 0 GLMR | ||||
| 4002201 | 925 days ago | 0 GLMR | ||||
| 4000935 | 925 days ago | 0 GLMR | ||||
| 3996089 | 926 days ago | 0 GLMR | ||||
| 3996067 | 926 days ago | 0 GLMR | ||||
| 3996064 | 926 days ago | 0 GLMR | ||||
| 3996055 | 926 days ago | 0 GLMR | ||||
| 3996052 | 926 days ago | 0 GLMR |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MissionsFacet
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 175 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/equippable/IERC6220.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol";
import "../interfaces/IDiscoverableLoot.sol";
import "../interfaces/IEvrlootResources.sol";
import "../libraries/Errors.sol";
import "../interfaces/IEvrlootMissions.sol";
import "../libraries/Sqrt.sol";
import {AppStorage, Modifiers, Staked} from "../libraries/LibAppStorage.sol";
import {LibMeta} from "../libraries/LibMeta.sol";
import "../interfaces/IQrng.sol";
import {IAssetAttributes} from "../interfaces/IAssetAttributes.sol";
// TODO: Add multi call for ending missions
// ?? address storageContractAddress;
contract MissionsFacet is IEvrlootMissions, Modifiers, IQrngClient {
using Strings for uint128;
/** @dev Max number of stored RNG values before restarting at index 0 */
uint64 constant MAX_RNGSTORE_LEN = 672;
/** @dev Establishes the granularity for rolls to 1/100,000 = 0.001% */
uint256 constant ROLL_RANGE = 100_000;
/** @dev optional fee to offset cost of on-chain rng */
constructor() {}
/**
* @notice Adds a new mission
* @dev Receives next available missionId
* @param nftRequirements NftByItemId[] array of NFT requirements
* @param resourceRequirements ResourceData[] array of resource requirements
* @param nftRewards NFTRewardChance[] array of NFT rewards
* @param resourceRewards ResourceRewardChance[] array of resource rewards
* @param activityData ActivityData struct (id, exp, and blockDuration)
*/
function addMission(
NftByItemId[] calldata nftRequirements,
ResourceData[] calldata resourceRequirements,
NFTRewardChance[] calldata nftRewards,
ResourceRewardChance[] calldata resourceRewards,
ActivityData calldata activityData
) public onlyOwnerOrBackend returns (uint256 missionId) {
missionId = s.missionNextId++;
for (uint256 i; i < nftRequirements.length; ) {
s.missionNftRequirements[missionId].push(nftRequirements[i]);
unchecked {
++i;
}
}
for (uint256 i; i < resourceRequirements.length; ) {
s.missionResourceRequirements[missionId].push(
resourceRequirements[i]
);
unchecked {
++i;
}
}
for (uint256 i; i < nftRewards.length; ) {
if (nftRewards[i].maxRolls > 13) {
revert MaxRollsExceedsLimit();
}
s.missionNftRewards[missionId].push(nftRewards[i]);
unchecked {
++i;
}
}
for (uint256 i; i < resourceRewards.length; ) {
s.missionResourceRewards[missionId].push(resourceRewards[i]);
unchecked {
++i;
}
}
s.missionActivityData[missionId] = activityData;
s._availableMissions.push(missionId);
emit MissionAdded(missionId);
}
/**
* @notice Starts a mission
* @param estraTokenId uint256 ID of the estra Token (received for staking)
* @param missionId uint16 ID of the mission
* @param suppliedNfts InputNftData[] array of NFTs supplied by the player
*/
function startMission(
uint256 estraTokenId,
uint16 missionId,
InputNftData[] memory suppliedNfts
)
public
payable
estraTokenHolder(estraTokenId)
noActiveOrUnclaimedMission(estraTokenId)
whenNotPaused
{
ActivityData memory missionActivityData = s.missionActivityData[
missionId
];
// Ensure this missionId exists and is not disabled
if (missionActivityData.blockDuration == 0)
revert MissionDoesNotExist();
if (missionActivityData.enabled == false) revert MissionNotEnabled();
// Check mission fee (if set)
if (s.missionFee != msg.value) revert IncorrectMissionFee();
// Check for gated collections
_verifyEstraTokenId(missionActivityData.collectionId, estraTokenId);
// Check for available Resources per mission requirements
_verifyAndBurnRequiredResources(missionId);
// Check for available NFTs per mission requirements
_verifyAndBurnRequiredNfts(missionId, suppliedNfts);
_startMission(
missionId,
estraTokenId,
missionActivityData.blockDuration
);
// Charge a minor fee to help reimburse rng calls
_chargeDistributedRngFee();
}
/**
* @notice Completes most recent mission. Stores awards by player address.
* @param estraTokenId - soul estraTokenId
*/
function endLastMission(
uint256 estraTokenId,
uint256 missionId
) public estraTokenHolder(estraTokenId) {
// read last player mission and then clear it
PlayerMission memory lastPlayerMission = s.lastPlayerMission[
estraTokenId
];
if (lastPlayerMission.missionId != missionId)
revert MissionIdMismatch();
if (lastPlayerMission.endBlock > block.number)
revert MissionNotFinished();
if (s.missionNextRngIndex > lastPlayerMission.rngIndex) {
delete s.lastPlayerMission[estraTokenId];
_endMission(estraTokenId, lastPlayerMission);
} else if (s._pendingMissionTokenId == 0) {
_requestUint256Rng();
s._pendingMissionTokenId = estraTokenId;
//_refundAirnodeFee(); TODO: check cost of this
} else {
revert NoRngAvailable(); // rng is pending
}
}
/**
* @notice Included in case the airnode fails to return an rng, resulting in a "stuck" mission
*/
function requestUint256Rng() public onlyOwnerOrBackend {
_requestUint256Rng();
}
/**
* @notice Withdraws fees to the feeWithdrawalAddress. Intent of fees is to support RNG costs.
*/
function withdrawFees() public onlyOwnerOrBackend {
if (address(this).balance > 0) revert NoFeestoCollect();
if (s.feeWithdrawalAddress == address(0))
revert WithdrawalAddressNotSet();
uint256 balance = address(this).balance;
(bool sent, ) = payable(s.feeWithdrawalAddress).call{value: (balance)}(
""
);
require(sent);
}
/**
* @notice Returns a view of the available missions
* @dev The indices provided (i.e. array positions) are to be used when calling startMission
*/
function availableMissions() public view returns (uint256[] memory) {
return s._availableMissions;
}
/**
* @notice Retrieves most recent player missions
* @param estraTokenId array of soul estraTokenIds
*/
function getLastMissionsByTokenIds(
uint256[] memory estraTokenId
) public view returns (PlayerMission[] memory missions) {
missions = new PlayerMission[](estraTokenId.length);
for (uint i; i < estraTokenId.length; ++i) {
missions[i] = s.lastPlayerMission[estraTokenId[i]];
}
}
/**
* @notice Returns a view of the mission data
* @param missionId uint256 ID of the mission
*/
function getMissionData(
uint256 missionId
)
public
view
returns (
ResourceData[] memory,
NftByItemId[] memory,
NFTRewardChance[] memory,
ResourceRewardChance[] memory,
ActivityData memory
)
{
return (
s.missionResourceRequirements[missionId],
s.missionNftRequirements[missionId],
s.missionNftRewards[missionId],
s.missionResourceRewards[missionId],
s.missionActivityData[missionId]
);
}
/**
* @notice Sets mission enabled/disabled
* @param missionId uint256 ID of the mission
* @param enabled bool whether the mission is enabled
*/
function setMissionEnabled(
uint256 missionId,
bool enabled
) public onlyOwnerOrBackend {
s.missionActivityData[missionId].enabled = enabled;
}
/**
* @dev internal function called by external fulfillUint256RngRequest (see EvrlootQrngClient)
* @dev pendingMissionTokenId is stored by a mission that tried to end but did not have an rng available
* @dev We also consider the case where pendingMissionTokenId is 0, meaning the call was made by
* @dev the backend to request an rng.
*/
function fulfillUint256RngRequest(
bytes32 requestId,
bytes memory data
) public onlyAirNode {
uint256 rngSeed = abi.decode(data, (uint256));
s.missionRolledRng[s.missionNextRngIndex % MAX_RNGSTORE_LEN] = rngSeed;
unchecked {
s.missionNextRngIndex = s.missionNextRngIndex + 1;
}
uint256 pendingMissionTokenId = s._pendingMissionTokenId;
if (pendingMissionTokenId != 0) {
PlayerMission memory lastPlayerMission = s.lastPlayerMission[
pendingMissionTokenId
];
s._pendingMissionTokenId = 0;
delete s.lastPlayerMission[pendingMissionTokenId];
_endMission(pendingMissionTokenId, lastPlayerMission);
}
emit MissionRoll(s.missionNextRngIndex - 1, rngSeed);
}
/* ============ Internal Functions ============ */
/**
* @dev Function adds RNG to the last mission of one or multiple soul tokenIds
* @dev this function implies that the backend ONLY passes RNG, then allows the player to finalize the mission
* @dev Including payable modifier makes this call cheaper by the backend (less opcodes to execute)
*
*/
function _requestUint256Rng() internal {
IQrngServer(s.qrngServerAddress).makeRequestUint256();
}
/**
* @notice Starts a mission
* @param missionId uint256 ID of the mission
* @param estraTokenId uint256 ID of the soul token
* @param blockDuration uint80 Duration of the mission in blocks
*/
function _startMission(
uint16 missionId,
uint256 estraTokenId,
uint32 blockDuration
) internal {
uint16 nextRngSeedIndex = uint16(
s.missionNextRngIndex % MAX_RNGSTORE_LEN
);
// Populate the PlayerMission struct
PlayerMission memory newPlayerMission = PlayerMission(
missionId,
LibMeta.msgSender(),
uint32(block.number) + blockDuration,
nextRngSeedIndex
);
s.lastPlayerMission[estraTokenId] = newPlayerMission;
emit MissionStarted(estraTokenId, missionId, nextRngSeedIndex);
}
/**
* @notice Completes most recent mission if it has exceeded block duration requirement
* @param estraTokenId uint256 ID of the soul token
* @param lastPlayerMission PlayerMission struct
*/
function _endMission(
uint256 estraTokenId,
PlayerMission memory lastPlayerMission
) private {
uint256 rngSeed = s.missionRolledRng[
lastPlayerMission.rngIndex % MAX_RNGSTORE_LEN
];
if (rngSeed < 2) revert NoRngAvailable(); // rngSeed entries are re-used after MAX_RNGSTORE_LEN (reset to 1), so both 0 and 1 are reserved
// Alter rngseed for the soulToken Id
rngSeed = uint256(keccak256(abi.encode(rngSeed, estraTokenId)));
// Load activity data and calculate activity level
ActivityData memory activityData = s.missionActivityData[
lastPlayerMission.missionId
];
(
address collection,
uint256 tokenId,
uint256 collectionId,
uint256 _activityLevel
) = _calculateActivityLevel(estraTokenId, activityData.activityId);
// Soul attributes (if soul collection, otherwise default to 0s)
uint16[] memory soulAttributes;
if (collectionId == 1) {
uint64[] memory soulAssets = IERC6220(collection).getActiveAssets(
tokenId
);
soulAttributes = IAssetAttributes(collection).getAttributes(
soulAssets[0],
true
);
} else {
soulAttributes = new uint16[](25);
}
// Resource rewards
_rollForResourceRewards(
lastPlayerMission,
rngSeed,
soulAttributes,
_activityLevel
);
// Nft rewards
_rollForNftRewards(
lastPlayerMission,
rngSeed,
soulAttributes,
_activityLevel
);
// Activity experience
uint256 rewardExperienceAmount = _getRewardExperience(
activityData.baseExperience,
activityData.attributeMultipliers,
soulAttributes
);
s.activityExperience[collection][tokenId][
activityData.activityId
] += rewardExperienceAmount;
emit MissionEnded(estraTokenId, lastPlayerMission.missionId);
}
/**
* @notice Computes the activity level of a soul based on its activity experience
* @dev Activity level is the greatest X in 2^(X+6) that divides into activityExperience
* @dev Level 0: 0-127, Level 1: 128-383, Level 2: 384-895, Level 3: 896-1919, Level 4: 1920-3967, Level 5: 3968-8063, etc.
*/
function _calculateActivityLevel(
uint256 estraTokenId,
uint16 activityId
)
internal
view
returns (
address collection,
uint256 tokenId,
uint256 collectionId,
uint256 _activityLevel
)
{
// get staking data
Staked memory _stakedTokenData = s.stakedTokens[estraTokenId];
collection = _stakedTokenData.collectionAddress;
tokenId = _stakedTokenData.tokenId;
collectionId = _stakedTokenData.collectionId;
uint256 activityExperience = s.activityExperience[collection][tokenId][
activityId
];
_activityLevel = 1;
unchecked {
while (activityExperience >= 2 ** (_activityLevel + 6)) {
_activityLevel++;
}
return (collection, tokenId, collectionId, _activityLevel - 1);
}
}
/**
* @notice Private function to roll for nft rewards
*/
function _rollForNftRewards(
PlayerMission memory lastPlayerMission,
uint256 rngSeed,
uint16[] memory soulAttributes,
uint256 _activityLevel
) internal {
// Determine NFT Rewards
NFTRewardChance[] memory _nftRewardChances = s.missionNftRewards[
lastPlayerMission.missionId
];
NftByItemId[] memory nftRewards = _getNftRewards(
_nftRewardChances,
rngSeed,
soulAttributes,
_activityLevel
);
// NFT rewards
for (uint j = 0; j < nftRewards.length; ) {
NftByItemId memory currentRewards = s.unclaimedNftRewards[
lastPlayerMission.playerAddress
][nftRewards[j].itemId];
if (currentRewards.amount != 0)
s
.unclaimedNftRewards[lastPlayerMission.playerAddress][
nftRewards[j].itemId
].amount = currentRewards.amount + nftRewards[j].amount;
else if (nftRewards[j].amount != 0) {
// We maintain an array of nft itemIds that have been rewarded to a player
s._unclaimedNftItemIds[lastPlayerMission.playerAddress].push(
nftRewards[j].itemId
);
s.unclaimedNftRewards[lastPlayerMission.playerAddress][
nftRewards[j].itemId
] = nftRewards[j];
}
unchecked {
++j;
}
}
}
function _rollForResourceRewards(
PlayerMission memory lastPlayerMission,
uint256 rngSeed,
uint16[] memory soulAttributes,
uint256 _activityLevel
) internal {
// Determine Resource Rewards
ResourceRewardChance[] memory _resourceRewardChances = s
.missionResourceRewards[lastPlayerMission.missionId];
ResourceData[] memory resourceRewards = _getResourceRewards(
_resourceRewardChances,
rngSeed,
soulAttributes,
_activityLevel
);
// Update stored rewards and experience
// Resource rewards
for (uint j = 0; j < resourceRewards.length; ) {
uint16 unclaimedAmount = s._unclaimedResourceRewards[
lastPlayerMission.playerAddress
][resourceRewards[j].resourceId];
if (unclaimedAmount != 0) {
s._unclaimedResourceRewards[lastPlayerMission.playerAddress][
resourceRewards[j].resourceId
] = unclaimedAmount + resourceRewards[j].amount;
} else if (resourceRewards[j].amount != 0) {
s._unclaimedResourceIds[lastPlayerMission.playerAddress].push(
resourceRewards[j].resourceId
);
s._unclaimedResourceRewards[lastPlayerMission.playerAddress][
resourceRewards[j].resourceId
] = resourceRewards[j].amount;
}
unchecked {
++j;
}
}
}
function _verifyEstraTokenId(
uint256 requiredCollectionId,
uint256 estraTokenId
) internal view {
if (requiredCollectionId == 0) return;
if (s.stakedTokens[estraTokenId].collectionId != requiredCollectionId)
revert UnsupportedMission();
return;
}
/**
* @notice Verifies player has required resources and burns them
* @param missionId uint256 ID of the mission
*/
function _verifyAndBurnRequiredResources(uint256 missionId) internal {
ResourceData[] memory neededResources = s.missionResourceRequirements[
missionId
];
uint256 remaining;
uint16 availableBalance;
for (uint i; i < neededResources.length; ) {
// Decrement the available reward balance by the amount needed for the mission
availableBalance = _unclaimedPlayerRewardResources(
neededResources[i].resourceId
);
if (availableBalance >= neededResources[i].amount) {
unchecked {
_setUnclaimedPlayerRewardResources(
neededResources[i].resourceId,
availableBalance - neededResources[i].amount
);
}
} else {
remaining = neededResources[i].amount - availableBalance;
_setUnclaimedPlayerRewardResources(
neededResources[i].resourceId,
0
);
// Burn remaining resources
// Note: The called contract will revert the tx if the player has insufficient resources
IEvrlootResources(s.resourcesContract).burn(
LibMeta.msgSender(),
neededResources[i].resourceId,
remaining
);
}
unchecked {
++i;
}
}
}
function _verifyAndBurnRequiredNfts(
uint256 missionId,
InputNftData[] memory suppliedNfts
) internal {
NftByItemId[] memory neededNfts = s.missionNftRequirements[missionId];
uint256 remaining = 0;
uint16 availableBalance;
for (uint i; i < neededNfts.length; ) {
availableBalance = _unclaimedPlayerRewards(neededNfts[i].itemId);
if (availableBalance >= neededNfts[i].amount) {
unchecked {
_setUnclaimedPlayerRewards(
neededNfts[i].itemId,
availableBalance - neededNfts[i].amount
);
}
} else {
remaining = neededNfts[i].amount - availableBalance;
delete s.unclaimedNftRewards[LibMeta.msgSender()][
neededNfts[i].itemId
];
// Transfer supplied nfts to the mission contract (up to what is additionally required)
// Note: Entire call will revert if an nft doesn't meet checks
if (remaining != 0) {
for (uint j = 0; j < suppliedNfts.length; ) {
if (_matchingNfts(suppliedNfts[j], neededNfts[i])) {
--remaining;
IERC6059(neededNfts[i].contractAddress).burn(
suppliedNfts[j].tokenId,
0
);
if (remaining == 0) {
break;
}
}
unchecked {
++j;
}
}
}
if (remaining != 0) {
revert InsufficientSuppliedNfts();
}
}
unchecked {
++i;
}
}
}
/**
* @notice Send funds to the Qrng sponsor wallet
*/
function _chargeDistributedRngFee() internal {
if (s.missionFee == 0) return;
(bool sent, ) = s.qrngSponsorWallet.call{value: msg.value}("");
if (!sent) {
revert FeeNotSent();
}
}
/**
* @notice Refunds the airnode gas costs back to player
*/
function _refundAirnodeFee() internal {
if (s.airnodeFee == 0) return;
uint256 balance = address(this).balance;
if (s.airnodeFee < balance) {
(bool sent, ) = payable(LibMeta.msgSender()).call{
value: (s.airnodeFee)
}(""); //9k gas
}
//if (!sent) {
// revert FeeNotSent();
// }
}
/**
* @dev Retrieve unclaimed reward resources
* @param resourceId Resource identifier
*/
function _unclaimedPlayerRewardResources(
uint256 resourceId
) internal view returns (uint16) {
return s._unclaimedResourceRewards[LibMeta.msgSender()][resourceId];
}
/**
* @dev Retrieve unclaimed reward nfts
* @param itemId itemId of the unclaimed reward NFT
*/
function _unclaimedPlayerRewards(
uint16 itemId
) internal view returns (uint16) {
return s.unclaimedNftRewards[LibMeta.msgSender()][itemId].amount;
}
/**
* @notice Determine NFTs to be rewarded
* @param nftRewardChances array indicates each NFT available for rewards along with roll mechanics
* @param baseRngSeed RNG seed
* @param soulAttributes array of soul attributes
*/
function _getNftRewards(
NFTRewardChance[] memory nftRewardChances,
uint256 baseRngSeed,
uint16[] memory soulAttributes,
uint256 _activityLevel
) internal pure returns (NftByItemId[] memory nftRewards) {
nftRewards = new NftByItemId[](nftRewardChances.length);
uint256 _rngSeed;
for (uint256 i; i < nftRewardChances.length; ) {
nftRewards[i] = NftByItemId(
nftRewardChances[i].contractAddress,
nftRewardChances[i].itemId,
0
);
_rngSeed = uint256(
keccak256(abi.encodePacked(baseRngSeed >> (2 * i), "NFTs"))
);
nftRewards[i].amount = _rollRewardAmount(
nftRewardChances[i].rollChance,
nftRewardChances[i].maxRolls,
nftRewardChances[i].attributeMultipliers,
nftRewardChances[i].experienceBenefit,
soulAttributes,
_activityLevel,
_rngSeed
);
unchecked {
++i;
}
}
}
/**
* @notice Determines the improvement to roll chance based on soul attributes and mission modifiers
* @param attributeMultipliers attribute multipliers stored within a single uint256 (purely for efficiency)
* @param soulAttributes array of soul attributes
* @return totalBenefit improvement to roll chance
*/
function _getRollModifier(
uint256 attributeMultipliers,
uint16[] memory soulAttributes,
uint256 _activityLevel,
uint8 experienceBenefit
) internal pure returns (uint16 totalBenefit) {
uint16 attributeBenefit = 0;
unchecked {
for (uint256 i; i < soulAttributes.length; ) {
// use bit shift to pull values out of attributeMultipliers, each with 10 bits
// 10 bits allows for a decimal place
attributeBenefit =
uint16(attributeMultipliers >> (10 * i)) &
0x3FF;
totalBenefit += (soulAttributes[i] * attributeBenefit); // square the attribute modifier
++i;
}
}
// Add in benefit from experience
totalBenefit += uint16(_activityLevel * (experienceBenefit ^ 2));
// Sqrt the result
totalBenefit = uint16(FixedPointMathLib.sqrt(totalBenefit));
}
/**
* @notice Determines quantity of each class of NFT provided
* @param rollChance possible NFT with roll mechanics
* @param maxRolls maximum number of rolls
* @param attributeMultipliers array of attribute multipliers
* @param soulAttributes array of soul attributes
* @param _activityLevel activity level
* @param rngSeed rng
*/
function _rollRewardAmount(
uint32 rollChance,
uint16 maxRolls,
uint256 attributeMultipliers,
uint8 experienceBenefit,
uint16[] memory soulAttributes,
uint256 _activityLevel,
uint256 rngSeed
) internal pure returns (uint16 amount) {
uint256 modifiedRollChance = rollChance +
_getRollModifier(
attributeMultipliers,
soulAttributes,
_activityLevel,
experienceBenefit
);
unchecked {
for (uint256 i; i < maxRolls; ) {
if ((rngSeed >> (i * 17)) % ROLL_RANGE < modifiedRollChance) {
// 17 bits shift per roll (256/17=14 independent rolls possible)
amount += 1;
} else {
return amount;
}
++i;
}
}
return amount;
}
/**
* @notice Determine resources to be rewarded
* @param resourceRewardChances array indicates each resource available for rewards along with roll mechanics
* @param baseRngSeed RNG seed
* @param soulAttributes array of soul attributes
*/
function _getResourceRewards(
ResourceRewardChance[] memory resourceRewardChances,
uint256 baseRngSeed,
uint16[] memory soulAttributes,
uint256 _activityLevel
) internal pure returns (ResourceData[] memory resourceRewards) {
resourceRewards = new ResourceData[](resourceRewardChances.length);
uint256 _rngSeed;
for (uint i; i < resourceRewardChances.length; ) {
resourceRewards[i] = ResourceData(
resourceRewardChances[i].resourceId,
0
);
_rngSeed = uint256(
keccak256(abi.encodePacked(baseRngSeed >> (2 * i), "Resources"))
);
resourceRewards[i].amount = _rollRewardAmount(
resourceRewardChances[i].rollChance,
resourceRewardChances[i].maxRolls,
resourceRewardChances[i].attributeMultipliers,
resourceRewardChances[i].experienceBenefit,
soulAttributes,
_activityLevel,
_rngSeed
);
unchecked {
++i;
}
}
}
/**
* @notice Determine experience to be rewarded
* @param baseExperience base experience to be rewarded
* @param attributeMultipliers array of attribute multipliers
* @param soulAttributes array of soul attributes
*/
function _getRewardExperience(
uint32 baseExperience,
uint256 attributeMultipliers,
uint16[] memory soulAttributes
) internal pure returns (uint256) {
uint256 totalBenefit = 0;
unchecked {
for (uint256 i; i < soulAttributes.length; ) {
// use bit shift to pull values out of attributeMultipliers, each with 10 bits
totalBenefit +=
soulAttributes[i] *
(uint16(attributeMultipliers >> (10 * i)) & 0x3FF);
++i;
}
}
return (totalBenefit * baseExperience * 10) / 1000 + baseExperience;
}
/**
* @dev Store unclaimed reward resources
* @param resourceId Resource identifier
* @param value Value to set
*/
function _setUnclaimedPlayerRewardResources(
uint256 resourceId,
uint16 value
) internal {
s._unclaimedResourceRewards[LibMeta.msgSender()][resourceId] = value;
}
/**
* @dev Store unclaimed reward nfts
* @param itemId itemId of the reward NFT
* @param value Value to set
*/
function _setUnclaimedPlayerRewards(uint16 itemId, uint16 value) internal {
s.unclaimedNftRewards[LibMeta.msgSender()][itemId].amount = value;
}
/** ============ Private Functions ============ */
function _matchingNfts(
InputNftData memory inputNft,
NftByItemId memory requiredNft
) private view returns (bool) {
if (inputNft.contractAddress != requiredNft.contractAddress)
return false;
uint16 itemId = IdentifiableLoot(inputNft.contractAddress).itemId(
inputNft.tokenId
);
if (requiredNft.itemId == itemId) return true;
// check if required memberId is 0 and the requiredNft is same pool as the inputNft
return (uint8(requiredNft.itemId) == 0 &&
requiredNft.itemId >> 8 == itemId >> 8); //Note itemId := poolId << 8 | memberId
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "../multiasset/IERC5773.sol";
/**
* @title IERC6220
* @author RMRK team
* @notice Interface smart contract of the RMRK equippable module.
*/
interface IERC6220 is IERC5773 {
/**
* @notice Used to store the core structure of the `Equippable` RMRK lego.
* @return assetId The ID of the asset equipping a child
* @return childAssetId The ID of the asset used as equipment
* @return childId The ID of token that is equipped
* @return childEquippableAddress Address of the collection to which the child asset belongs to
*/
struct Equipment {
uint64 assetId;
uint64 childAssetId;
uint256 childId;
address childEquippableAddress;
}
/**
* @notice Used to provide a struct for inputing equip data.
* @dev Only used for input and not storage of data.
* @return tokenId ID of the token we are managing
* @return childIndex Index of a child in the list of token's active children
* @return assetId ID of the asset that we are equipping into
* @return slotPartId ID of the slot part that we are using to equip
* @return childAssetId ID of the asset that we are equipping
*/
struct IntakeEquip {
uint256 tokenId;
uint256 childIndex;
uint64 assetId;
uint64 slotPartId;
uint64 childAssetId;
}
/**
* @notice Used to notify listeners that a child's asset has been equipped into one of its parent assets.
* @param tokenId ID of the token that had an asset equipped
* @param assetId ID of the asset associated with the token we are equipping into
* @param slotPartId ID of the slot we are using to equip
* @param childId ID of the child token we are equipping into the slot
* @param childAddress Address of the child token's collection
* @param childAssetId ID of the asset associated with the token we are equipping
*/
event ChildAssetEquipped(
uint256 indexed tokenId,
uint64 indexed assetId,
uint64 indexed slotPartId,
uint256 childId,
address childAddress,
uint64 childAssetId
);
/**
* @notice Used to notify listeners that a child's asset has been unequipped from one of its parent assets.
* @param tokenId ID of the token that had an asset unequipped
* @param assetId ID of the asset associated with the token we are unequipping out of
* @param slotPartId ID of the slot we are unequipping from
* @param childId ID of the token being unequipped
* @param childAddress Address of the collection that a token that is being unequipped belongs to
* @param childAssetId ID of the asset associated with the token we are unequipping
*/
event ChildAssetUnequipped(
uint256 indexed tokenId,
uint64 indexed assetId,
uint64 indexed slotPartId,
uint256 childId,
address childAddress,
uint64 childAssetId
);
/**
* @notice Used to notify listeners that the assets belonging to a `equippableGroupId` have been marked as
* equippable into a given slot and parent
* @param equippableGroupId ID of the equippable group being marked as equippable into the slot associated with
* `slotPartId` of the `parentAddress` collection
* @param slotPartId ID of the slot part of the catalog into which the parts belonging to the equippable group
* associated with `equippableGroupId` can be equipped
* @param parentAddress Address of the collection into which the parts belonging to `equippableGroupId` can be
* equipped
*/
event ValidParentEquippableGroupIdSet(
uint64 indexed equippableGroupId,
uint64 indexed slotPartId,
address parentAddress
);
/**
* @notice Used to equip a child into a token.
* @dev The `IntakeEquip` stuct contains the following data:
* [
* tokenId,
* childIndex,
* assetId,
* slotPartId,
* childAssetId
* ]
* @param data An `IntakeEquip` struct specifying the equip data
*/
function equip(IntakeEquip memory data) external;
/**
* @notice Used to unequip child from parent token.
* @dev This can only be called by the owner of the token or by an account that has been granted permission to
* manage the given token by the current owner.
* @param tokenId ID of the parent from which the child is being unequipped
* @param assetId ID of the parent's asset that contains the `Slot` into which the child is equipped
* @param slotPartId ID of the `Slot` from which to unequip the child
*/
function unequip(
uint256 tokenId,
uint64 assetId,
uint64 slotPartId
) external;
/**
* @notice Used to check whether the token has a given child equipped.
* @dev This is used to prevent from transferring a child that is equipped.
* @param tokenId ID of the parent token for which we are querying for
* @param childAddress Address of the child token's smart contract
* @param childId ID of the child token
* @return A boolean value indicating whether the child token is equipped into the given token or not
*/
function isChildEquipped(
uint256 tokenId,
address childAddress,
uint256 childId
) external view returns (bool);
/**
* @notice Used to verify whether a token can be equipped into a given parent's slot.
* @param parent Address of the parent token's smart contract
* @param tokenId ID of the token we want to equip
* @param assetId ID of the asset associated with the token we want to equip
* @param slotId ID of the slot that we want to equip the token into
* @return A boolean indicating whether the token with the given asset can be equipped into the desired slot
*/
function canTokenBeEquippedWithAssetIntoSlot(
address parent,
uint256 tokenId,
uint64 assetId,
uint64 slotId
) external view returns (bool);
/**
* @notice Used to get the Equipment object equipped into the specified slot of the desired token.
* @dev The `Equipment` struct consists of the following data:
* [
* assetId,
* childAssetId,
* childId,
* childEquippableAddress
* ]
* @param tokenId ID of the token for which we are retrieving the equipped object
* @param targetCatalogAddress Address of the `Catalog` associated with the `Slot` part of the token
* @param slotPartId ID of the `Slot` part that we are checking for equipped objects
* @return The `Equipment` struct containing data about the equipped object
*/
function getEquipment(
uint256 tokenId,
address targetCatalogAddress,
uint64 slotPartId
) external view returns (Equipment memory);
/**
* @notice Used to get the asset and equippable data associated with given `assetId`.
* @param tokenId ID of the token for which to retrieve the asset
* @param assetId ID of the asset of which we are retrieving
* @return metadataURI The metadata URI of the asset
* @return equippableGroupId ID of the equippable group this asset belongs to
* @return catalogAddress The address of the catalog the part belongs to
* @return partIds An array of IDs of parts included in the asset
*/
function getAssetAndEquippableData(
uint256 tokenId,
uint64 assetId
)
external
view
returns (
string memory metadataURI,
uint64 equippableGroupId,
address catalogAddress,
uint64[] memory partIds
);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @title IERC5773
* @author RMRK team
* @notice Interface smart contract of the RMRK multi asset module.
*/
interface IERC5773 is IERC165 {
/**
* @notice Used to notify listeners that an asset object is initialized at `assetId`.
* @param assetId ID of the asset that was initialized
*/
event AssetSet(uint64 indexed assetId);
/**
* @notice Used to notify listeners that an asset object at `assetId` is added to token's pending asset
* array.
* @param tokenIds An array of token IDs that received a new pending asset
* @param assetId ID of the asset that has been added to the token's pending assets array
* @param replacesId ID of the asset that would be replaced
*/
event AssetAddedToTokens(
uint256[] tokenIds,
uint64 indexed assetId,
uint64 indexed replacesId
);
/**
* @notice Used to notify listeners that an asset object at `assetId` is accepted by the token and migrated
* from token's pending assets array to active assets array of the token.
* @param tokenId ID of the token that had a new asset accepted
* @param assetId ID of the asset that was accepted
* @param replacesId ID of the asset that was replaced
*/
event AssetAccepted(
uint256 indexed tokenId,
uint64 indexed assetId,
uint64 indexed replacesId
);
/**
* @notice Used to notify listeners that an asset object at `assetId` is rejected from token and is dropped
* from the pending assets array of the token.
* @param tokenId ID of the token that had an asset rejected
* @param assetId ID of the asset that was rejected
*/
event AssetRejected(uint256 indexed tokenId, uint64 indexed assetId);
/**
* @notice Used to notify listeners that token's prioritiy array is reordered.
* @param tokenId ID of the token that had the asset priority array updated
*/
event AssetPrioritySet(uint256 indexed tokenId);
/**
* @notice Used to notify listeners that owner has granted an approval to the user to manage the assets of a
* given token.
* @dev Approvals must be cleared on transfer
* @param owner Address of the account that has granted the approval for all token's assets
* @param approved Address of the account that has been granted approval to manage the token's assets
* @param tokenId ID of the token on which the approval was granted
*/
event ApprovalForAssets(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);
/**
* @notice Used to notify listeners that owner has granted approval to the user to manage assets of all of their
* tokens.
* @param owner Address of the account that has granted the approval for all assets on all of their tokens
* @param operator Address of the account that has been granted the approval to manage the token's assets on all of
* the tokens
* @param approved Boolean value signifying whether the permission has been granted (`true`) or revoked (`false`)
*/
event ApprovalForAllForAssets(
address indexed owner,
address indexed operator,
bool approved
);
/**
* @notice Accepts an asset at from the pending array of given token.
* @dev Migrates the asset from the token's pending asset array to the token's active asset array.
* @dev Active assets cannot be removed by anyone, but can be replaced by a new asset.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* - `index` must be in range of the length of the pending asset array.
* @dev Emits an {AssetAccepted} event.
* @param tokenId ID of the token for which to accept the pending asset
* @param index Index of the asset in the pending array to accept
* @param assetId ID of the asset expected to be in the index
*/
function acceptAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) external;
/**
* @notice Rejects an asset from the pending array of given token.
* @dev Removes the asset from the token's pending asset array.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* - `index` must be in range of the length of the pending asset array.
* @dev Emits a {AssetRejected} event.
* @param tokenId ID of the token that the asset is being rejected from
* @param index Index of the asset in the pending array to be rejected
* @param assetId ID of the asset expected to be in the index
*/
function rejectAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) external;
/**
* @notice Rejects all assets from the pending array of a given token.
* @dev Effecitvely deletes the pending array.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* @dev Emits a {AssetRejected} event with assetId = 0.
* @param tokenId ID of the token of which to clear the pending array.
* @param maxRejections Maximum number of expected assets to reject, used to prevent from rejecting assets which
* arrive just before this operation.
*/
function rejectAllAssets(uint256 tokenId, uint256 maxRejections) external;
/**
* @notice Sets a new priority array for a given token.
* @dev The priority array is a non-sequential list of `uint64`s, where the lowest value is considered highest
* priority.
* @dev Value `0` of a priority is a special case equivalent to unitialized.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* - The length of `priorities` must be equal the length of the active assets array.
* @dev Emits a {AssetPrioritySet} event.
* @param tokenId ID of the token to set the priorities for
* @param priorities An array of priorities of active assets. The succesion of items in the priorities array
* matches that of the succesion of items in the active array
*/
function setPriority(
uint256 tokenId,
uint64[] calldata priorities
) external;
/**
* @notice Used to retrieve IDs of the active assets of given token.
* @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
* `getAssetMetadata(tokenId, assetId)`.
* @dev You can safely get 10k
* @param tokenId ID of the token to retrieve the IDs of the active assets
* @return An array of active asset IDs of the given token
*/
function getActiveAssets(
uint256 tokenId
) external view returns (uint64[] memory);
/**
* @notice Used to retrieve IDs of the pending assets of given token.
* @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
* `getAssetMetadata(tokenId, assetId)`.
* @param tokenId ID of the token to retrieve the IDs of the pending assets
* @return An array of pending asset IDs of the given token
*/
function getPendingAssets(
uint256 tokenId
) external view returns (uint64[] memory);
/**
* @notice Used to retrieve the priorities of the active resoources of a given token.
* @dev Asset priorities are a non-sequential array of uint64 values with an array size equal to active asset
* priorites.
* @param tokenId ID of the token for which to retrieve the priorities of the active assets
* @return An array of priorities of the active assets of the given token
*/
function getActiveAssetPriorities(
uint256 tokenId
) external view returns (uint64[] memory);
/**
* @notice Used to retrieve the asset that will be replaced if a given asset from the token's pending array
* is accepted.
* @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
* `getAssetMetadata(tokenId, assetId)`.
* @param tokenId ID of the token to check
* @param newAssetId ID of the pending asset which will be accepted
* @return ID of the asset which will be replaced
*/
function getAssetReplacements(
uint256 tokenId,
uint64 newAssetId
) external view returns (uint64);
/**
* @notice Used to fetch the asset metadata of the specified token's active asset with the given index.
* @dev Assets are stored by reference mapping `_assets[assetId]`.
* @dev Can be overriden to implement enumerate, fallback or other custom logic.
* @param tokenId ID of the token from which to retrieve the asset metadata
* @param assetId Asset Id, must be in the active assets array
* @return The metadata of the asset belonging to the specified index in the token's active assets
* array
*/
function getAssetMetadata(
uint256 tokenId,
uint64 assetId
) external view returns (string memory);
// Approvals
/**
* @notice Used to grant permission to the user to manage token's assets.
* @dev This differs from transfer approvals, as approvals are not cleared when the approved party accepts or
* rejects an asset, or sets asset priorities. This approval is cleared on token transfer.
* @dev Only a single account can be approved at a time, so approving the `0x0` address clears previous approvals.
* @dev Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
* @dev Emits an {ApprovalForAssets} event.
* @param to Address of the account to grant the approval to
* @param tokenId ID of the token for which the approval to manage the assets is granted
*/
function approveForAssets(address to, uint256 tokenId) external;
/**
* @notice Used to retrieve the address of the account approved to manage assets of a given token.
* @dev Requirements:
*
* - `tokenId` must exist.
* @param tokenId ID of the token for which to retrieve the approved address
* @return Address of the account that is approved to manage the specified token's assets
*/
function getApprovedForAssets(
uint256 tokenId
) external view returns (address);
/**
* @notice Used to add or remove an operator of assets for the caller.
* @dev Operators can call {acceptAsset}, {rejectAsset}, {rejectAllAssets} or {setPriority} for any token
* owned by the caller.
* @dev Requirements:
*
* - The `operator` cannot be the caller.
* @dev Emits an {ApprovalForAllForAssets} event.
* @param operator Address of the account to which the operator role is granted or revoked from
* @param approved The boolean value indicating whether the operator role is being granted (`true`) or revoked
* (`false`)
*/
function setApprovalForAllForAssets(
address operator,
bool approved
) external;
/**
* @notice Used to check whether the address has been granted the operator role by a given address or not.
* @dev See {setApprovalForAllForAssets}.
* @param owner Address of the account that we are checking for whether it has granted the operator role
* @param operator Address of the account that we are checking whether it has the operator role or not
* @return A boolean value indicating wehter the account we are checking has been granted the operator role
*/
function isApprovedForAllForAssets(
address owner,
address operator
) external view returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @title IERC6059
* @author RMRK team
* @notice Interface smart contract of the RMRK nestable module.
*/
interface IERC6059 is IERC165 {
/**
* @notice The core struct of RMRK ownership.
* @dev The `DirectOwner` struct is used to store information of the next immediate owner, be it the parent token or
* the externally owned account.
* @dev If the token is owned by the externally owned account, the `tokenId` should equal `0`.
* @param tokenId ID of the parent token
* @param ownerAddress Address of the owner of the token. If the owner is another token, then the address should be
* the one of the parent token's collection smart contract. If the owner is externally owned account, the address
* should be the address of this account
* @param isNft A boolean value signifying whether the token is owned by another token (`true`) or by an externally
* owned account (`false`)
*/
struct DirectOwner {
uint256 tokenId;
address ownerAddress;
}
/**
* @notice Used to notify listeners that the token is being transferred.
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
* @param from Address of the previous immediate owner, which is a smart contract if the token was nested.
* @param to Address of the new immediate owner, which is a smart contract if the token is being nested.
* @param fromTokenId ID of the previous parent token. If the token was not nested before, the value should be `0`
* @param toTokenId ID of the new parent token. If the token is not being nested, the value should be `0`
* @param tokenId ID of the token being transferred
*/
event NestTransfer(
address indexed from,
address indexed to,
uint256 fromTokenId,
uint256 toTokenId,
uint256 indexed tokenId
);
/**
* @notice Used to notify listeners that a new token has been added to a given token's pending children array.
* @dev Emitted when a child NFT is added to a token's pending array.
* @param tokenId ID of the token that received a new pending child token
* @param childIndex Index of the proposed child token in the parent token's pending children array
* @param childAddress Address of the proposed child token's collection smart contract
* @param childId ID of the child token in the child token's collection smart contract
*/
event ChildProposed(
uint256 indexed tokenId,
uint256 childIndex,
address indexed childAddress,
uint256 indexed childId
);
/**
* @notice Used to notify listeners that a new child token was accepted by the parent token.
* @dev Emitted when a parent token accepts a token from its pending array, migrating it to the active array.
* @param tokenId ID of the token that accepted a new child token
* @param childIndex Index of the newly accepted child token in the parent token's active children array
* @param childAddress Address of the child token's collection smart contract
* @param childId ID of the child token in the child token's collection smart contract
*/
event ChildAccepted(
uint256 indexed tokenId,
uint256 childIndex,
address indexed childAddress,
uint256 indexed childId
);
/**
* @notice Used to notify listeners that all pending child tokens of a given token have been rejected.
* @dev Emitted when a token removes all a child tokens from its pending array.
* @param tokenId ID of the token that rejected all of the pending children
*/
event AllChildrenRejected(uint256 indexed tokenId);
/**
* @notice Used to notify listeners a child token has been transferred from parent token.
* @dev Emitted when a token transfers a child from itself, transferring ownership to the root owner.
* @param tokenId ID of the token that transferred a child token
* @param childIndex Index of a child in the array from which it is being transferred
* @param childAddress Address of the child token's collection smart contract
* @param childId ID of the child token in the child token's collection smart contract
* @param fromPending A boolean value signifying whether the token was in the pending child tokens array (`true`) or
* in the active child tokens array (`false`)
* @param toZero A boolean value signifying whether the token is being transferred to the `0x0` address (`true`) or
* not (`false`)
*/
event ChildTransferred(
uint256 indexed tokenId,
uint256 childIndex,
address indexed childAddress,
uint256 indexed childId,
bool fromPending,
bool toZero
);
/**
* @notice The core child token struct, holding the information about the child tokens.
* @return tokenId ID of the child token in the child token's collection smart contract
* @return contractAddress Address of the child token's smart contract
*/
struct Child {
uint256 tokenId;
address contractAddress;
}
/**
* @notice Used to retrieve the *root* owner of a given token.
* @dev The *root* owner of the token is an externally owned account (EOA). If the given token is child of another
* NFT, this will return an EOA address. Otherwise, if the token is owned by an EOA, this EOA wil be returned.
* @param tokenId ID of the token for which the *root* owner has been retrieved
* @return owner The *root* owner of the token
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @notice Used to retrieve the immediate owner of the given token.
* @dev If the immediate owner is another token, the address returned, should be the one of the parent token's
* collection smart contract.
* @param tokenId ID of the token for which the RMRK owner is being retrieved
* @return Address of the given token's owner
* @return The ID of the parent token. Should be `0` if the owner is an externally owned account
* @return The boolean value signifying whether the owner is an NFT or not
*/
function directOwnerOf(
uint256 tokenId
) external view returns (address, uint256, bool);
/**
* @notice Used to burn a given token.
* @dev When a token is burned, all of its child tokens are recursively burned as well.
* @dev When specifying the maximum recursive burns, the execution will be reverted if there are more children to be
* burned.
* @dev Setting the `maxRecursiveBurn` value to 0 will only attempt to burn the specified token and revert if there
* are any child tokens present.
* @dev The approvals are cleared when the token is burned.
* @dev Requirements:
*
* - `tokenId` must exist.
* @dev Emits a {Transfer} event.
* @param tokenId ID of the token to burn
* @param maxRecursiveBurns Maximum number of tokens to recursively burn
* @return Number of recursively burned children
*/
function burn(
uint256 tokenId,
uint256 maxRecursiveBurns
) external returns (uint256);
/**
* @notice Used to add a child token to a given parent token.
* @dev This adds the child token into the given parent token's pending child tokens array.
* @dev Requirements:
*
* - `directOwnerOf` on the child contract must resolve to the called contract.
* - the pending array of the parent contract must not be full.
* @param parentId ID of the parent token to receive the new child token
* @param childId ID of the new proposed child token
* @param data Additional data with no specified format
*/
function addChild(
uint256 parentId,
uint256 childId,
bytes memory data
) external;
/**
* @notice Used to accept a pending child token for a given parent token.
* @dev This moves the child token from parent token's pending child tokens array into the active child tokens
* array.
* @param parentId ID of the parent token for which the child token is being accepted
* @param childIndex Index of a child tokem in the given parent's pending children array
* @param childAddress Address of the collection smart contract of the child token expected to be located at the
* specified index of the given parent token's pending children array
* @param childId ID of the child token expected to be located at the specified index of the given parent token's
* pending children array
*/
function acceptChild(
uint256 parentId,
uint256 childIndex,
address childAddress,
uint256 childId
) external;
/**
* @notice Used to reject all pending children of a given parent token.
* @dev Removes the children from the pending array mapping.
* @dev This does not update the ownership storage data on children. If necessary, ownership can be reclaimed by the
* rootOwner of the previous parent.
* @dev Requirements:
*
* Requirements:
*
* - `parentId` must exist
* @param parentId ID of the parent token for which to reject all of the pending tokens.
* @param maxRejections Maximum number of expected children to reject, used to prevent from rejecting children which
* arrive just before this operation.
*/
function rejectAllChildren(
uint256 parentId,
uint256 maxRejections
) external;
/**
* @notice Used to transfer a child token from a given parent token.
* @dev When transferring a child token, the owner of the token is set to `to`, or is not updated in the event of
* `to` being the `0x0` address.
* @param tokenId ID of the parent token from which the child token is being transferred
* @param to Address to which to transfer the token to
* @param destinationId ID of the token to receive this child token (MUST be 0 if the destination is not a token)
* @param childIndex Index of a token we are transferring, in the array it belongs to (can be either active array or
* pending array)
* @param childAddress Address of the child token's collection smart contract.
* @param childId ID of the child token in its own collection smart contract.
* @param isPending A boolean value indicating whether the child token being transferred is in the pending array of
* the parent token (`true`) or in the active array (`false`)
* @param data Additional data with no specified format, sent in call to `_to`
*/
function transferChild(
uint256 tokenId,
address to,
uint256 destinationId,
uint256 childIndex,
address childAddress,
uint256 childId,
bool isPending,
bytes memory data
) external;
/**
* @notice Used to retrieve the active child tokens of a given parent token.
* @dev Returns array of Child structs existing for parent token.
* @dev The Child struct consists of the following values:
* [
* tokenId,
* contractAddress
* ]
* @param parentId ID of the parent token for which to retrieve the active child tokens
* @return An array of Child structs containing the parent token's active child tokens
*/
function childrenOf(
uint256 parentId
) external view returns (Child[] memory);
/**
* @notice Used to retrieve the pending child tokens of a given parent token.
* @dev Returns array of pending Child structs existing for given parent.
* @dev The Child struct consists of the following values:
* [
* tokenId,
* contractAddress
* ]
* @param parentId ID of the parent token for which to retrieve the pending child tokens
* @return An array of Child structs containing the parent token's pending child tokens
*/
function pendingChildrenOf(
uint256 parentId
) external view returns (Child[] memory);
/**
* @notice Used to retrieve a specific active child token for a given parent token.
* @dev Returns a single Child struct locating at `index` of parent token's active child tokens array.
* @dev The Child struct consists of the following values:
* [
* tokenId,
* contractAddress
* ]
* @param parentId ID of the parent token for which the child is being retrieved
* @param index Index of the child token in the parent token's active child tokens array
* @return A Child struct containing data about the specified child
*/
function childOf(
uint256 parentId,
uint256 index
) external view returns (Child memory);
/**
* @notice Used to retrieve a specific pending child token from a given parent token.
* @dev Returns a single Child struct locating at `index` of parent token's active child tokens array.
* @dev The Child struct consists of the following values:
* [
* tokenId,
* contractAddress
* ]
* @param parentId ID of the parent token for which the pending child token is being retrieved
* @param index Index of the child token in the parent token's pending child tokens array
* @return A Child struct containting data about the specified child
*/
function pendingChildOf(
uint256 parentId,
uint256 index
) external view returns (Child memory);
/**
* @notice Used to transfer the token into another token.
* @param from Address of the direct owner of the token to be transferred
* @param to Address of the receiving token's collection smart contract
* @param tokenId ID of the token being transferred
* @param destinationId ID of the token to receive the token being transferred
* @param data Additional data with no specified format, sent in the addChild call
*/
function nestTransferFrom(
address from,
address to,
uint256 tokenId,
uint256 destinationId,
bytes memory data
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAssetAttributes {
function getAttributes(
uint256 tokenId,
bool getTotal
) external view returns (uint16[] memory);
function setAttributes(
uint256 tokenId,
uint16[] memory attributes
) external;
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ interface IDiamond { enum FacetCutAction {Add, Replace, Remove} // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; FacetCutAction action; bytes4[] functionSelectors; } event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ import {IDiamond} from "./IDiamond.sol"; import {IERC165Updater} from "./IERC165Updater.sol"; interface IDiamondCut is IDiamond, IERC165Updater { /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; }
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
interface IdentifiableLoot {
function setItemId(uint256 tokenId, uint64 itemId) external;
function itemId(uint256 tokenId) external view returns (uint16);
function poolId(uint256 tokenId) external view returns (uint16);
function memberId(uint256 tokenId) external view returns (uint16);
function ownerOf(uint256 tokenId) external view returns (address owner);
function batchAddNewAssetsToTokens(
uint256 tokenId,
uint64 assetIds,
uint64 replacesAssetWithId,
uint16 setsItemId
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IERC165Updater
* @author Multiple
* @notice An extension of ERC165 Standard Interface Detection that allows contracts to add and remove supported interfaces.
*
* Users can check for interface support via `supportsInterface(bytes4 interfaceID)` as defined in ERC165. Users can add or remove interface support via [`updateSupportedInterfaces()`](#updatesupportedinterfaces).
*/
interface IERC165Updater {
/// @notice Emitted when support for an interface is updated.
event InterfaceSupportUpdated(bytes4 indexed interfaceID, bool supported);
/**
* @notice Adds or removes supported interfaces.
* @dev Add access control in implementation.
* @param interfaceIDs The list of interfaces to update.
* @param support The list of true to signal support, false otherwise.
*/
function updateSupportedInterfaces(
bytes4[] calldata interfaceIDs,
bool[] calldata support
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @notice Struct used for claiming rewards.
* @param id is the id of the reward to claim
* @param index is the index of the reward to claim
* @param amount is the amount of the reward to claim
*/
struct claimItem {
uint16 id;
uint16 index;
uint16 amount;
}
/**
* @notice NFT Information used for supplying nfts to startMission function
* @dev The player must provide approval for the contract to transfer the NFT
* @param contractAddress is the address of the NFT contract
* @param tokenId is the token id of the NFT
*/
struct InputNftData {
address contractAddress;
uint256 tokenId;
}
/**
* @notice Each mission contains one or multiple NFT rewards with preset roll characteristics
* @param contractAddress is the address of the NFT contract
* @param poolId is the mint index of the NFT
* @param amount is the amount of the NFT to mint
* @param rollChance rollChance/100_000 chance of rolling this reward
* @param maxRolls Player rolls until they fail, or up to maxRolls
* @param attributeMultipliers array of 16 uint16s multiplied by soul attributes to determine roll benefit
*/
struct NFTRewardChance {
// 2 slots total
address contractAddress;
uint16 itemId;
uint16 amount;
uint32 rollChance;
uint16 maxRolls;
uint8 experienceBenefit; // 256
uint256 attributeMultipliers; // 256
}
/**
* @notice NFT Information use for minting and mission requirements
* @param contractAddress is the address of the NFT contract
* @param poolId is the mint index of the NFT
* @param amount is the amount of the NFT to mint
*/
struct NftByItemId {
// 1 slot
address contractAddress; // 160
uint16 itemId;
uint16 amount; // 208
}
/**
* @notice Earned (already rolled) resource rewards
* @param resourceId is the id of the resource
* @param amount is the amount of the resource
*/
struct ResourceData {
uint16 resourceId;
uint16 amount;
}
/**
* @notice Each mission contains one or multiple Resource rewards with preset roll characteristics
* @param resourceData struct containing the resource id and amount of the reward
* @param rollChance rollChance/100_000 chance of rolling this reward
* @param maxRolls Player rolls until they fail, or up to maxRolls
* @param attributeMultipliers Multiplier for each attribute x10 (Max multipler is 25.5). 0 = no multiplier
* @dev note that attributeMultipliers
*/
struct ResourceRewardChance {
uint16 resourceId;
uint16 amount;
uint32 rollChance;
uint8 maxRolls;
uint8 experienceBenefit; // 80
uint256 attributeMultipliers; // 256
}
/**
* @notice Specific reward amount for an activity associated to a mission.
* @dev ActivityRewards are stored by soul tokenId and incremented following mission completion.
* @param enabled is a bool to enable/disable the mission
* @param blockDuration is the duration of the mission in blocks
* @param activityId is the id of the activity effected by this mission
* @param baseExperience is the base experience reward for completing the mission
* @param collectionId is the id of the supported collection within the staking contract
*/
struct ActivityData {
bool enabled;
uint32 blockDuration;
uint16 activityId;
uint32 baseExperience;
uint32 collectionId; //120
uint256 attributeMultipliers; // 256
}
/**
* @notice PlayerMission struct
* @dev Only the Most recent PlayerMission is stored. It is mapped to the soul tokenId which created it.
* @param missionId is the id of the mission.
* @param playerAddress is the address of the player who started the mission.
* @param endBlock is the block the playerMission completes.
*/
struct PlayerMission {
uint16 missionId; // 16
address playerAddress; // 176
uint32 endBlock; // 240
uint32 rngIndex; // 256
}
interface IEvrlootMissions {
//events
event MissionAdded(uint256 indexed missionId);
event MissionStarted(
uint256 indexed tokenId,
uint16 indexed missionId,
uint256 rngIndex
);
event MissionEnded(uint256 indexed tokenId, uint16 indexed missionId);
event MissionRoll(uint256 rngIndex, uint256 rolledValue);
function getLastMissionsByTokenIds(
uint256[] memory tokenId
) external view returns (PlayerMission[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
interface IEvrlootResources {
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
function mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) external;
function burnBatch(
address account,
uint256[] memory ids,
uint256[] memory amounts
) external;
function burn(address account, uint256 id, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
struct inputToken {
address contractAddress;
uint256 tokenId;
}
struct RollableAssets {
uint64[] assetIds;
uint16 itemId;
}
interface IIdentify {
event RequestRNG(address playerAddress, uint256 tokenId);
function identify(inputToken[] memory inputTokens) external;
function isIdentifiable(
address[] memory contractAddress,
uint256[] memory tokenId
) external view returns (bool[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
interface IQrngServer {
function makeRequestUint256() external;
}
interface IQrngClient {
function fulfillUint256RngRequest(
bytes32 requestId,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT pragma solidity 0.8.19; error ZeroAddress(); error UnsupportedMission(); error NotSoulCollection(); error NotSupportedCollection(); error CollectionAlreadyExists(); error MissionDoesNotExist(); error MissionNotEnabled(); error MissionNotStarted(); error MissionNotFinished(); error MissionNotFinalized(); error InsufficientAttributes(); error NotMissionPlayer(); error IncorrectMissionFee(); error InvalidRewardAmount(); error InvalidRewardIndex(); error InvalidRewardAddress(); error SenderIsNotOwnerOfStakedToken(); error SoulHasActiveOrUnclaimedMission(); error InvalidIndex(); error InsufficientSuppliedNfts(); error FeeNotSent(); error RequestedAmountZero(); error NotSoulTokenOwner(); error NotEstraTokenOwner(); error BadInputLengths(); error NotErc721TokenOwner(); error NoFeestoCollect(); error WithdrawalAddressNotSet(); error MaxRollsExceedsLimit(); error AlreadyIdentified(); error PoolIdNotSet(); error ItemIdAlreadySet(); error ContractNotSupported(); error NotTokenOwner(); error NoRngAvailable(); error WithdrawFailed(); error RMRKMintUnderpriced(); error RMRKMintZero(); error NotChildTokenOwner(); error MissionIdMismatch(); error ContractIsPaused(); error ContractIsNotPaused(); error NotAirNode(); error ResourceMetadataNotSet(); error InvalidTokenID();
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {LibDiamond} from "./LibDiamond.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../interfaces/IIdentify.sol";
import "./Errors.sol";
import "../interfaces/IEvrlootMissions.sol";
struct Staked {
address collectionAddress; // 160
uint32 tokenId; // 192
uint32 collectionId; // 224
}
struct Rental {
uint32 collectionId; // 32
uint32 tokenId; // 64
uint32 estraTokenId; // 96
uint64 rentalPrice; // 160
uint32 rentalStart; // 192
uint32 rentalEnd; // 224
}
struct ActiveRental {
address renter;
uint32 estraTokenId;
uint32 rentalStart;
uint32 rentalEnd;
}
struct AppStorage {
string name;
bool paused;
address missionContract;
address expeditionContract;
address marketContract;
address battleContract;
address resourcesContract;
/**
*
* ====== ERC721 Staking Variables ===== */
// Token name
string stakingTokenName;
// Token symbol
string stakingTokenSymbol;
// Mapping from token ID to owner address
mapping(uint256 => address) stakingTokenOwners;
// Mapping owner address to token count
mapping(address => uint256) stakingTokenBalances;
// Mapping from token ID to approved address
mapping(uint256 => address) stakingTokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) stakingOperatorApprovals;
mapping(address => mapping(uint256 => uint256)) stakingOwnedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) stakingOwnedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] stakingAllTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) stakingAllTokensIndex;
string stakingBaseURIString;
// estraTokenId => Staked
mapping(uint256 => Staked) stakedTokens;
// collectionAddress => tokenId => estraTokenId
mapping(address => mapping(uint256 => uint256)) stakedSoulTokens;
// collectionAddress => collectionId
mapping(address => uint256) stakedCollectionId;
// collectionId => tokenUri
mapping(uint256 => string) stakedTokenURI; // mapping of index to tokenURI
// collectionId => isEnumerable
mapping(uint256 => uint8) stakedIsEnumerable; // mapping of index to isEnumerable
uint256 stakedLastCollectionId;
uint256 stakedLastEstraTokenId;
uint256 soulCollectionIndex;
/**
*
* ====== Mission Variables ====== */
uint256 missionFee;
uint256 airnodeFee;
address evrSoulsContractAddress;
address backendAddress;
address feeWithdrawalAddress;
uint64 missionNextRngIndex; // max index will be 672 (2 weeks of rng values assuming 1 per 30 minutes)
uint256 _pendingMissionTokenId;
uint256[] _availableMissions;
uint256 missionNextId;
/** @dev Mission properties are stored in mappings to uint256 missionId
* The inner mission structs are pulled out int his way to avoid complications with
* nested struct arrays. */
mapping(uint256 => ResourceData[]) missionResourceRequirements; //32
mapping(uint256 => NftByItemId[]) missionNftRequirements;
mapping(uint256 => NFTRewardChance[]) missionNftRewards;
mapping(uint256 => ResourceRewardChance[]) missionResourceRewards;
mapping(uint256 => ActivityData) missionActivityData; // includes blockDuration
/** @dev Most recent player mission mapped to soul tokenId */
mapping(uint256 => PlayerMission) lastPlayerMission;
/** @dev Unclaimed NFT Rewards mapping
* playerAddress => NFT itemId => NftByItemId struct */
mapping(address => mapping(uint16 => NftByItemId)) unclaimedNftRewards;
/** @dev Unclaimed Nfts as an array of itemId (poolId & memberId)
* playerAddress => NFT itemId
* useful for tracking NFT types stored in _unclaimedNftRewards mapping */
mapping(address => uint16[]) _unclaimedNftItemIds;
/** @dev Unclaimed Resource Rewards mapping
* playerAddress => resourceID => count */
mapping(address => mapping(uint256 => uint16)) _unclaimedResourceRewards;
/** @dev Unclaimed Resources as an array of Resource Ids
* playerAddress => resourceID as array
* Useful for tracking resource IDs stored in _unclaimedResourceRewards mapping */
mapping(address => uint16[]) _unclaimedResourceIds;
/** @dev Activity Experience mapping
* soul tokenID => activityId => count */
mapping(address => mapping(uint256 => mapping(uint16 => uint256))) activityExperience;
/** @dev rng is mapped to the soulTokenId once it is received from the qrng contract
* this is necessary to avoid gaming the rng value -- waiting to end mission until a favorable value is received
* Thus the first rng returned since mission start is used for the mission
* note that rng values are returned every n blocks */
mapping(uint256 => uint256) missionRolledRng;
/**
*
* ====== QRNG Variables ====== */
address qrngServerAddress;
address airnodeAddress;
address qrngSponsorWallet;
bytes32 pendingRngRequestId;
/**
*
* ====== Item Identification Variables ====== */
mapping(address => mapping(uint16 => RollableAssets[])) identifyRollableAssets; // address as NFT Contract, uint16 as poolId
address[] identifySupportedContracts;
mapping(address => bool) identifyIsSupportedContract;
mapping(address => mapping(uint256 => bool)) isIdentified;
/**
*
* ====== Soul Trait Variables ====== */
mapping(uint256 => uint256) uint8SoulTraits;
/**
*
* ====== Rental Variables ====== */
mapping(uint256 => Rental) rentableTokens;
mapping(address => uint256) rentableCollections;
/**
*
* ====== Transaction Signing (EIP 712) ====== */
bytes32 domainSeparator;
mapping(address => uint256) metaNonces;
}
library LibAppStorage {
function diamondStorage() internal pure returns (AppStorage storage ds) {
assembly {
ds.slot := 0
}
}
function abs(int256 x) internal pure returns (uint256) {
return uint256(x >= 0 ? x : -x);
}
}
/** ============ Modifiers ============ */
contract Modifiers {
AppStorage internal s;
modifier onlyOwner() {
LibDiamond.enforceIsContractOwner();
_;
}
modifier onlyOwnerOrBackend() {
LibDiamond.enforceIsContractOwnerOrBackendAddress();
_;
}
/**
* @dev Make a function callable only when msg sender owns the supplied estraTokenId
* @param estraTokenId uint256 ID of the receipt token to validate
*/
modifier estraTokenHolder(uint256 estraTokenId) {
if (address(0) == s.stakingTokenOwners[estraTokenId])
revert InvalidTokenID();
if (msg.sender != s.stakingTokenOwners[estraTokenId])
revert SenderIsNotOwnerOfStakedToken();
_;
}
modifier isSoulCollection(address collectionAddress) {
if (s.stakedCollectionId[collectionAddress] != s.soulCollectionIndex)
revert NotSoulCollection();
_;
}
modifier supportedCollection(address collectionAddress) {
if (s.stakedCollectionId[collectionAddress] == 0)
revert NotSupportedCollection();
_;
}
/**
* @dev Make a function callable only when soul estraTokenId is not on an active mission
* @param estraTokenId uint256 ID of the token to validate
*/
modifier noActiveOrUnclaimedMission(uint256 estraTokenId) {
if (s.lastPlayerMission[estraTokenId].endBlock != 0)
revert SoulHasActiveOrUnclaimedMission();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
if (s.paused) revert ContractIsPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
if (!s.paused) revert ContractIsNotPaused();
_;
}
/**
* @dev Make a function callable only by the QRNG contract
*/
modifier onlyAirNode() {
if (msg.sender != s.airnodeAddress) revert NotAirNode();
_;
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ import {IDiamond} from "../interfaces/IDiamond.sol"; import {IDiamondCut} from "../interfaces/IDiamondCut.sol"; // Remember to add the loupe functions from DiamondLoupeFacet to the diamond. // The loupe functions are required by the EIP2535 Diamonds standard error NoSelectorsGivenToAdd(); error NotContractOwner(address _user, address _contractOwner); error NotPermitted( address _user, address _contractOwner, address _backendAddress ); error NoSelectorsProvidedForFacetForCut(address _facetAddress); error CannotAddSelectorsToZeroAddress(bytes4[] _selectors); error NoBytecodeAtAddress(address _contractAddress, string _message); error IncorrectFacetCutAction(uint8 _action); error CannotAddFunctionToDiamondThatAlreadyExists(bytes4 _selector); error CannotReplaceFunctionsFromFacetWithZeroAddress(bytes4[] _selectors); error CannotReplaceImmutableFunction(bytes4 _selector); error CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet( bytes4 _selector ); error CannotReplaceFunctionThatDoesNotExists(bytes4 _selector); error RemoveFacetAddressMustBeZeroAddress(address _facetAddress); error CannotRemoveFunctionThatDoesNotExist(bytes4 _selector); error CannotRemoveImmutableFunction(bytes4 _selector); error InitializationFunctionReverted( address _initializationContractAddress, bytes _calldata ); library LibDiamond { bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage"); struct FacetAddressAndSelectorPosition { address facetAddress; uint16 selectorPosition; } struct DiamondStorage { // function selector => facet address and selector position in selectors array mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition; bytes4[] selectors; mapping(bytes4 => bool) supportedInterfaces; // owner of the contract address contractOwner; address backendAddress; } function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } } event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); } function contractOwner() internal view returns (address contractOwner_) { contractOwner_ = diamondStorage().contractOwner; } function enforceIsContractOwner() internal view { if (msg.sender != diamondStorage().contractOwner) { revert NotContractOwner(msg.sender, diamondStorage().contractOwner); } } function enforceIsContractOwnerOrBackendAddress() internal view { DiamondStorage storage ds = diamondStorage(); if (msg.sender != ds.backendAddress && msg.sender != ds.contractOwner) { revert NotPermitted( msg.sender, diamondStorage().contractOwner, diamondStorage().backendAddress ); } } event DiamondCut( IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata ); // Internal function version of diamondCut function diamondCut( IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata ) internal { for ( uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++ ) { bytes4[] memory functionSelectors = _diamondCut[facetIndex] .functionSelectors; address facetAddress = _diamondCut[facetIndex].facetAddress; if (functionSelectors.length == 0) { revert NoSelectorsProvidedForFacetForCut(facetAddress); } IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action; if (action == IDiamond.FacetCutAction.Add) { addFunctions(facetAddress, functionSelectors); } else if (action == IDiamond.FacetCutAction.Replace) { replaceFunctions(facetAddress, functionSelectors); } else if (action == IDiamond.FacetCutAction.Remove) { removeFunctions(facetAddress, functionSelectors); } else { revert IncorrectFacetCutAction(uint8(action)); } } emit DiamondCut(_diamondCut, _init, _calldata); initializeDiamondCut(_init, _calldata); } function addFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { if (_facetAddress == address(0)) { revert CannotAddSelectorsToZeroAddress(_functionSelectors); } DiamondStorage storage ds = diamondStorage(); uint16 selectorCount = uint16(ds.selectors.length); enforceHasContractCode( _facetAddress, "LibDiamondCut: Add facet has no code" ); for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .facetAddressAndSelectorPosition[selector] .facetAddress; if (oldFacetAddress != address(0)) { revert CannotAddFunctionToDiamondThatAlreadyExists(selector); } ds.facetAddressAndSelectorPosition[ selector ] = FacetAddressAndSelectorPosition( _facetAddress, selectorCount ); ds.selectors.push(selector); selectorCount++; } } function replaceFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { DiamondStorage storage ds = diamondStorage(); if (_facetAddress == address(0)) { revert CannotReplaceFunctionsFromFacetWithZeroAddress( _functionSelectors ); } enforceHasContractCode( _facetAddress, "LibDiamondCut: Replace facet has no code" ); for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .facetAddressAndSelectorPosition[selector] .facetAddress; // can't replace immutable functions -- functions defined directly in the diamond in this case if (oldFacetAddress == address(this)) { revert CannotReplaceImmutableFunction(selector); } if (oldFacetAddress == _facetAddress) { revert CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet( selector ); } if (oldFacetAddress == address(0)) { revert CannotReplaceFunctionThatDoesNotExists(selector); } // replace old facet address ds .facetAddressAndSelectorPosition[selector] .facetAddress = _facetAddress; } } function removeFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { DiamondStorage storage ds = diamondStorage(); uint256 selectorCount = ds.selectors.length; if (_facetAddress != address(0)) { revert RemoveFacetAddressMustBeZeroAddress(_facetAddress); } for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; FacetAddressAndSelectorPosition memory oldFacetAddressAndSelectorPosition = ds .facetAddressAndSelectorPosition[selector]; if (oldFacetAddressAndSelectorPosition.facetAddress == address(0)) { revert CannotRemoveFunctionThatDoesNotExist(selector); } // can't remove immutable functions -- functions defined directly in the diamond if ( oldFacetAddressAndSelectorPosition.facetAddress == address(this) ) { revert CannotRemoveImmutableFunction(selector); } // replace selector with last selector selectorCount--; if ( oldFacetAddressAndSelectorPosition.selectorPosition != selectorCount ) { bytes4 lastSelector = ds.selectors[selectorCount]; ds.selectors[ oldFacetAddressAndSelectorPosition.selectorPosition ] = lastSelector; ds .facetAddressAndSelectorPosition[lastSelector] .selectorPosition = oldFacetAddressAndSelectorPosition .selectorPosition; } // delete last selector ds.selectors.pop(); delete ds.facetAddressAndSelectorPosition[selector]; } } function initializeDiamondCut( address _init, bytes memory _calldata ) internal { if (_init == address(0)) { return; } enforceHasContractCode( _init, "LibDiamondCut: _init address has no code" ); (bool success, bytes memory error) = _init.delegatecall(_calldata); if (!success) { if (error.length > 0) { // bubble up error /// @solidity memory-safe-assembly assembly { let returndata_size := mload(error) revert(add(32, error), returndata_size) } } else { revert InitializationFunctionReverted(_init, _calldata); } } } function enforceHasContractCode( address _contract, string memory _errorMessage ) internal view { uint256 contractSize; assembly { contractSize := extcodesize(_contract) } if (contractSize == 0) { revert NoBytecodeAtAddress(_contract, _errorMessage); } } }
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
library LibMeta {
bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
keccak256(
bytes(
"EIP712Domain(string name,string version,uint256 salt,address verifyingContract)"
)
);
function domainSeparator(
string memory name,
string memory version
) internal view returns (bytes32 domainSeparator_) {
domainSeparator_ = keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(bytes(name)),
keccak256(bytes(version)),
getChainID(),
address(this)
)
);
}
function getChainID() internal view returns (uint256 id) {
assembly {
id := chainid()
}
}
function msgSender() internal view returns (address sender_) {
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
sender_ := and(
mload(add(array, index)),
0xffffffffffffffffffffffffffffffffffffffff
)
}
} else {
sender_ = msg.sender;
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
// based on https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol
library FixedPointMathLib {
function sqrt(uint256 x) internal pure returns (uint256 z) {
assembly {
// This segment is to get a reasonable initial estimate for the Babylonian method.
// If the initial estimate is bad, the number of correct bits increases ~linearly
// each iteration instead of ~quadratically.
// The idea is to get z*z*y within a small factor of x.
// More iterations here gets y in a tighter range. Currently, we will have
// y in [256, 256*2^16). We ensure y>= 256 so that the relative difference
// between y and y+1 is small. If x < 256 this is not possible, but those cases
// are easy enough to verify exhaustively.
z := 181 // The 'correct' value is 1, but this saves a multiply later
let y := x
// Note that we check y>= 2^(k + 8) but shift right by k bits each branch,
// this is to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8),
// and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of x, or about 20bps.
// The estimate sqrt(x) = (181/1024) * (x+1) is off by a factor of ~2.83 both when x=1
// and when x = 256 or 1/256. In the worst case, this needs seven Babylonian iterations.
z := shr(18, mul(z, add(y, 65536))) // A multiply is saved from the initial z := 181
// Run the Babylonian method seven times. This should be enough given initial estimate.
// Possibly with a quadratic/cubic polynomial above we could get 4-6.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// See https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division.
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This check ensures we return floor.
// The solmate implementation assigns zRoundDown := div(x, z) first, but
// since this case is rare, we choose to save gas on the assignment and
// repeat division in the rare case.
// If you don't care whether floor or ceil is returned, you can skip this.
if lt(div(x, z), z) {
z := div(x, z)
}
}
}
}{
"optimizer": {
"enabled": true,
"runs": 175
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ContractIsPaused","type":"error"},{"inputs":[],"name":"FeeNotSent","type":"error"},{"inputs":[],"name":"IncorrectMissionFee","type":"error"},{"inputs":[],"name":"InsufficientSuppliedNfts","type":"error"},{"inputs":[],"name":"InvalidTokenID","type":"error"},{"inputs":[],"name":"MaxRollsExceedsLimit","type":"error"},{"inputs":[],"name":"MissionDoesNotExist","type":"error"},{"inputs":[],"name":"MissionIdMismatch","type":"error"},{"inputs":[],"name":"MissionNotEnabled","type":"error"},{"inputs":[],"name":"MissionNotFinished","type":"error"},{"inputs":[],"name":"NoFeestoCollect","type":"error"},{"inputs":[],"name":"NoRngAvailable","type":"error"},{"inputs":[],"name":"NotAirNode","type":"error"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_contractOwner","type":"address"},{"internalType":"address","name":"_backendAddress","type":"address"}],"name":"NotPermitted","type":"error"},{"inputs":[],"name":"SenderIsNotOwnerOfStakedToken","type":"error"},{"inputs":[],"name":"SoulHasActiveOrUnclaimedMission","type":"error"},{"inputs":[],"name":"UnsupportedMission","type":"error"},{"inputs":[],"name":"WithdrawalAddressNotSet","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"missionId","type":"uint256"}],"name":"MissionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint16","name":"missionId","type":"uint16"}],"name":"MissionEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rngIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rolledValue","type":"uint256"}],"name":"MissionRoll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint16","name":"missionId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"rngIndex","type":"uint256"}],"name":"MissionStarted","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint16","name":"itemId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"}],"internalType":"struct NftByItemId[]","name":"nftRequirements","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"resourceId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"}],"internalType":"struct ResourceData[]","name":"resourceRequirements","type":"tuple[]"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint16","name":"itemId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"},{"internalType":"uint32","name":"rollChance","type":"uint32"},{"internalType":"uint16","name":"maxRolls","type":"uint16"},{"internalType":"uint8","name":"experienceBenefit","type":"uint8"},{"internalType":"uint256","name":"attributeMultipliers","type":"uint256"}],"internalType":"struct NFTRewardChance[]","name":"nftRewards","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"resourceId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"},{"internalType":"uint32","name":"rollChance","type":"uint32"},{"internalType":"uint8","name":"maxRolls","type":"uint8"},{"internalType":"uint8","name":"experienceBenefit","type":"uint8"},{"internalType":"uint256","name":"attributeMultipliers","type":"uint256"}],"internalType":"struct ResourceRewardChance[]","name":"resourceRewards","type":"tuple[]"},{"components":[{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint32","name":"blockDuration","type":"uint32"},{"internalType":"uint16","name":"activityId","type":"uint16"},{"internalType":"uint32","name":"baseExperience","type":"uint32"},{"internalType":"uint32","name":"collectionId","type":"uint32"},{"internalType":"uint256","name":"attributeMultipliers","type":"uint256"}],"internalType":"struct ActivityData","name":"activityData","type":"tuple"}],"name":"addMission","outputs":[{"internalType":"uint256","name":"missionId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"availableMissions","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"estraTokenId","type":"uint256"},{"internalType":"uint256","name":"missionId","type":"uint256"}],"name":"endLastMission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"fulfillUint256RngRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"estraTokenId","type":"uint256[]"}],"name":"getLastMissionsByTokenIds","outputs":[{"components":[{"internalType":"uint16","name":"missionId","type":"uint16"},{"internalType":"address","name":"playerAddress","type":"address"},{"internalType":"uint32","name":"endBlock","type":"uint32"},{"internalType":"uint32","name":"rngIndex","type":"uint32"}],"internalType":"struct PlayerMission[]","name":"missions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"missionId","type":"uint256"}],"name":"getMissionData","outputs":[{"components":[{"internalType":"uint16","name":"resourceId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"}],"internalType":"struct ResourceData[]","name":"","type":"tuple[]"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint16","name":"itemId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"}],"internalType":"struct NftByItemId[]","name":"","type":"tuple[]"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint16","name":"itemId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"},{"internalType":"uint32","name":"rollChance","type":"uint32"},{"internalType":"uint16","name":"maxRolls","type":"uint16"},{"internalType":"uint8","name":"experienceBenefit","type":"uint8"},{"internalType":"uint256","name":"attributeMultipliers","type":"uint256"}],"internalType":"struct NFTRewardChance[]","name":"","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"resourceId","type":"uint16"},{"internalType":"uint16","name":"amount","type":"uint16"},{"internalType":"uint32","name":"rollChance","type":"uint32"},{"internalType":"uint8","name":"maxRolls","type":"uint8"},{"internalType":"uint8","name":"experienceBenefit","type":"uint8"},{"internalType":"uint256","name":"attributeMultipliers","type":"uint256"}],"internalType":"struct ResourceRewardChance[]","name":"","type":"tuple[]"},{"components":[{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint32","name":"blockDuration","type":"uint32"},{"internalType":"uint16","name":"activityId","type":"uint16"},{"internalType":"uint32","name":"baseExperience","type":"uint32"},{"internalType":"uint32","name":"collectionId","type":"uint32"},{"internalType":"uint256","name":"attributeMultipliers","type":"uint256"}],"internalType":"struct ActivityData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestUint256Rng","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"missionId","type":"uint256"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setMissionEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"estraTokenId","type":"uint256"},{"internalType":"uint16","name":"missionId","type":"uint16"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct InputNftData[]","name":"suppliedNfts","type":"tuple[]"}],"name":"startMission","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b506139ad806100206000396000f3fe6080604052600436106100915760003560e01c8063476343ee11610059578063476343ee1461015557806361b80af11461016a578063b68787371461017f578063bdcad3db1461019f578063f25747e0146101bf57600080fd5b806304c86e791461009657806308e50a2c146100c15780630fa1ecc3146100ef578063143a28e7146101205780632661bacf14610135575b600080fd5b3480156100a257600080fd5b506100ab6101ec565b6040516100b89190612abe565b60405180910390f35b3480156100cd57600080fd5b506100e16100dc366004612be7565b610247565b6040519081526020016100b8565b3480156100fb57600080fd5b5061010f61010a366004612cea565b6104c7565b6040516100b8959493929190612e6b565b61013361012e366004613004565b6107ed565b005b34801561014157600080fd5b506101336101503660046130e4565b6109e6565b34801561016157600080fd5b50610133610b8d565b34801561017657600080fd5b50610133610c45565b34801561018b57600080fd5b5061013361019a366004613182565b610c57565b3480156101ab57600080fd5b506101336101ba3660046131b2565b610dfd565b3480156101cb57600080fd5b506101df6101da3660046131e2565b610e25565b6040516100b89190613267565b60606000601f0180548060200260200160405190810160405280929190818152602001828054801561023d57602002820191906000526020600020905b815481526020019060010190808311610229575b5050505050905090565b6000610251610f57565b60208054906000610261836132f7565b91905055905060005b898110156102c85760008281526022602052604090208b8b8381811061029257610292613310565b835460018101855560009485526020909420606090910292909201929190910190506102be8282613384565b505060010161026a565b5060005b8781101561032a5760008281526021602052604090208989838181106102f4576102f4613310565b8354600181018555600094855260209094206040909102929092019291909101905061032082826133d0565b50506001016102cc565b5060005b858110156103dd57600d87878381811061034a5761034a613310565b905060e0020160800160208101906103629190613415565b61ffff16111561038557604051633cc4479360e11b815260040160405180910390fd5b60008281526023602052604090208787838181106103a5576103a5613310565b83546001810185556000948552602090942060e0909102929092019260020290910190506103d38282613462565b505060010161032e565b5060005b8381101561044157600082815260246020526040902085858381811061040957610409613310565b83546001810185556000948552602090942060c0909102929092019260020290910190506104378282613542565b50506001016103e1565b506000818152602560205260409020829061045c8282613619565b5050601f805460018101825560009182527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d8070182905560405182917fa110ffa8dafcbc1768f2a7031ffc4a4a62a3429ad91f3172c875ddeb637cd30591a29998505050505050505050565b6040805160c0810182526000808252602080830182905282840182905260608084018390526080840183905260a08401839052858352602182528483206022835285842060238452868520602485528786206025865288872084548a5181890281018901909b52808b5295998a998a998a999198889290919084015b82821015610586576000848152602090819020604080518082019091529084015461ffff8082168352620100009091041681830152825260019092019101610543565b50505050945083805480602002602001604051908101604052809291908181526020016000905b8282101561060557600084815260209081902060408051606081018252918501546001600160a01b038116835261ffff600160a01b8204811684860152600160b01b90910416908201528252600190920191016105ad565b50505050935082805480602002602001604051908101604052809291908181526020016000905b828210156106c85760008481526020908190206040805160e0810182526002860290920180546001600160a01b0381168452600160a01b810461ffff90811685870152600160b01b8204811693850193909352600160c01b810463ffffffff166060850152600160e01b81049092166080840152600160f01b90910460ff1660a083015260019081015460c0830152908352909201910161062c565b50505050925081805480602002602001604051908101604052809291908181526020016000905b828210156107755760008481526020908190206040805160c08101825260028602909201805461ffff8082168552620100008204168486015263ffffffff6401000000008204169284019290925260ff600160401b830481166060850152600160481b909204909116608083015260019081015460a083015290835290920191016106ef565b50506040805160c081018252855460ff81161515825263ffffffff61010082048116602084015261ffff600160281b83041693830193909352600160381b810483166060830152600160581b9004909116608082015260019094015460a085015250959c949b50929950919750909550909350505050565b60008381526008602052604081205484916001600160a01b03909116900361082857604051636aa2a93760e01b815260040160405180910390fd5b6000818152600860205260409020546001600160a01b0316331461085f5760405163daceb5e160e01b815260040160405180910390fd5b6000848152602660205260409020548490600160b01b900463ffffffff161561089b57604051635fd30cb160e01b815260040160405180910390fd5b60015460ff16156108bf576040516306d39fcd60e41b815260040160405180910390fd5b61ffff8085166000908152602560209081526040808320815160c081018352815460ff81161515825263ffffffff61010082048116958301869052600160281b820490971693820193909352600160381b830486166060820152600160581b909204909416608082015260019093015460a084015290036109535760405163b98b9c9f60e01b815260040160405180910390fd5b8051151560000361097757604051639d46cd6960e01b815260040160405180910390fd5b60195434146109985760405162a57da360e31b815260040160405180910390fd5b6109ac816080015163ffffffff1687611044565b6109b98561ffff1661108b565b6109c78561ffff16856112c1565b6109d6858783602001516115e2565b6109de61170f565b505050505050565b602e546001600160a01b03163314610a1157604051637b1fc71560e01b815260040160405180910390fd5b600081806020019051810190610a279190613704565b601d549091508190602c90600090610a52906102a090600160a01b90046001600160401b0316613733565b6001600160401b039081168252602082019290925260400160002091909155601d805467ffffffffffffffff60a01b198116600160a01b91829004841660010190931602919091179055601e548015610b255760008181526026602081815260408084208151608081018352815461ffff811682526001600160a01b03620100008204168286015263ffffffff600160b01b8204811694830194909452600160d01b90049092166060830152601e8590559385905291905281546001600160f01b031916909155610b23828261178f565b505b601d547f95095a68d304f692d102eb2d6bed743a6dfc02ff677525aba527e9666c39b99d90610b6690600190600160a01b90046001600160401b0316613759565b604080516001600160401b039092168252602082018590520160405180910390a150505050565b610b95610f57565b4715610bb45760405163774a4bd560e11b815260040160405180910390fd5b601d546001600160a01b0316610bdd57604051637c4ca5fd60e11b815260040160405180910390fd5b601d5460405147916000916001600160a01b039091169083908381818185875af1925050503d8060008114610c2e576040519150601f19603f3d011682016040523d82523d6000602084013e610c33565b606091505b5050905080610c4157600080fd5b5050565b610c4d610f57565b610c55611aa1565b565b60008281526008602052604081205483916001600160a01b039091169003610c9257604051636aa2a93760e01b815260040160405180910390fd5b6000818152600860205260409020546001600160a01b03163314610cc95760405163daceb5e160e01b815260040160405180910390fd5b6000838152602660209081526040918290208251608081018452905461ffff81168083526001600160a01b03620100008304169383019390935263ffffffff600160b01b8204811694830194909452600160d01b900490921660608301528314610d46576040516337ec0c6b60e11b815260040160405180910390fd5b43816040015163ffffffff161115610d715760405163a0da2a8160e01b815260040160405180910390fd5b6060810151601d5463ffffffff909116600160a01b9091046001600160401b03161115610dc357600084815260266020526040902080546001600160f01b0319169055610dbe848261178f565b610df7565b601e54600003610ddf57610dd5611aa1565b601e849055610df7565b60405162b419e560e01b815260040160405180910390fd5b50505050565b610e05610f57565b600091825260256020526040909120805460ff1916911515919091179055565b606081516001600160401b03811115610e4057610e40612f5e565b604051908082528060200260200182016040528015610e9257816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181610e5e5790505b50905060005b8251811015610f515760006026016000848381518110610eba57610eba613310565b60209081029190910181015182528181019290925260409081016000208151608081018352905461ffff811682526001600160a01b03620100008204169382019390935263ffffffff600160b01b8404811692820192909252600160d01b9092041660608201528251839083908110610f3557610f35613310565b602002602001018190525080610f4a906132f7565b9050610e98565b50919050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c1320547fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c906001600160a01b03163314801590610fc0575060038101546001600160a01b03163314155b15611041577fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f547fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c1320546040805162a87e2b60e41b81523360048201526001600160a01b03938416602482015291909216604482015290519081900360640190fd5b50565b81600003611050575050565b600081815260116020526040902054600160c01b900463ffffffff168214610c41576040516313205c1960e21b815260040160405180910390fd5b600081815260216020908152604080832080548251818502810185019093528083529192909190849084015b828210156110fa576000848152602090819020604080518082019091529084015461ffff80821683526201000090910416818301528252600190920191016110b7565b50505050905060008060005b83518110156112ba5761113984828151811061112457611124613310565b60200260200101516000015161ffff16611afb565b915083818151811061114d5761114d613310565b60200260200101516020015161ffff168261ffff16106111b6576111b184828151811061117c5761117c613310565b60200260200101516000015161ffff1685838151811061119e5761119e613310565b6020026020010151602001518403611b3a565b6112b2565b818482815181106111c9576111c9613310565b6020026020010151602001516111df9190613780565b61ffff1692506112118482815181106111fa576111fa613310565b60200260200101516000015161ffff166000611b3a565b6005546001600160a01b031663f5298aca61122a611b96565b86848151811061123c5761123c613310565b6020908102919091010151516040516001600160e01b031960e085901b1681526001600160a01b03909216600483015261ffff16602482015260448101869052606401600060405180830381600087803b15801561129957600080fd5b505af11580156112ad573d6000803e3d6000fd5b505050505b600101611106565b5050505050565b600082815260226020908152604080832080548251818502810185019093528083529192909190849084015b8282101561134557600084815260209081902060408051606081018252918501546001600160a01b038116835261ffff600160a01b8204811684860152600160b01b90910416908201528252600190920191016112ed565b505050509050600080805b83518110156109de5761137f84828151811061136e5761136e613310565b602002602001015160200151611bf2565b915083818151811061139357611393613310565b60200260200101516040015161ffff168261ffff16106113f8576113f38482815181106113c2576113c2613310565b6020026020010151602001518583815181106113e0576113e0613310565b6020026020010151604001518403611c3a565b6115da565b8184828151811061140b5761140b613310565b6020026020010151604001516114219190613780565b61ffff16925060276000611433611b96565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085838151811061146757611467613310565b60209081029190910181015181015161ffff16825281019190915260400160002080546001600160c01b031916905582156115bb5760005b85518110156115b9576114e48682815181106114bd576114bd613310565b60200260200101518684815181106114d7576114d7613310565b6020026020010151611c8f565b156115b1576114f28461379b565b935084828151811061150657611506613310565b6020026020010151600001516001600160a01b031663b390c0ab87838151811061153257611532613310565b60200260200101516020015160006040518363ffffffff1660e01b8152600401611566929190918252602082015260400190565b6020604051808303816000875af1158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a99190613704565b5083156115b9575b60010161149f565b505b82156115da57604051631f69f0e760e11b815260040160405180910390fd5b600101611350565b601d54600090611605906102a090600160a01b90046001600160401b0316613733565b9050600060405180608001604052808661ffff168152602001611626611b96565b6001600160a01b0316815260200161163e85436137b2565b63ffffffff908116825261ffff858116602093840181905260008981526026855260409081902086518154888801518985015160608b01518916600160d01b0263ffffffff60d01b1991909916600160b01b021667ffffffffffffffff60b01b196001600160a01b0390921662010000026001600160b01b0319909316938816939093179190911716179490941790935591519182529293509187169186917f1f8ac8b0980dabac3fd0ccee4885164cb997f4553e44e20cf8bfbeb789f150c5910160405180910390a35050505050565b60195460000361171b57565b602f546040516000916001600160a01b03169034908381818185875af1925050503d8060008114611768576040519150601f19603f3d011682016040523d82523d6000602084013e61176d565b606091505b505090508061104157604051630a6b029160e11b815260040160405180910390fd5b600080602c0160006102a0846060015163ffffffff166117af9190613733565b6001600160401b0316815260200190815260200160002054905060028110156117ea5760405162b419e560e01b815260040160405180910390fd5b604080516020810183905290810184905260600160408051601f198184030181528282528051602091820120855161ffff90811660009081526025845284812060c087018652805460ff81161515885263ffffffff6101008204811696890196909652600160281b8104909316958701869052600160381b830485166060880152600160581b90920490931660808601526001015460a0850152935090819081908190611898908990611d72565b93509350935093506060826001036119c457604051633940140f60e11b8152600481018590526000906001600160a01b03871690637280281e90602401600060405180830381865afa1580156118f2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261191a91908101906137cf565b9050856001600160a01b0316633600261d8260008151811061193e5761193e613310565b60209081029190910101516040516001600160e01b031960e084901b1681526001600160401b03909116600482015260016024820152604401600060405180830381865afa158015611994573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119bc9190810190613873565b9150506119e8565b60408051601980825261034082019092529060208201610320803683370190505090505b6119f488888385611e0e565b611a0088888385612137565b6000611a1587606001518860a00151846124e4565b6001600160a01b0387166000908152602b6020908152604080832089845282528083208b82015161ffff168452909152812080549293508392909190611a5c908490613901565b9091555050885160405161ffff909116908b907f93ec5673fed993d7e6454e9a6d078ea74b0622e3caed8fbe98c36f340ef718d390600090a350505050505050505050565b602d546040805163dea12bad60e01b815290516001600160a01b039092169163dea12bad9160048082019260009290919082900301818387803b158015611ae757600080fd5b505af1158015610df7573d6000803e3d6000fd5b6000602981611b08611b96565b6001600160a01b0316815260208082019290925260409081016000908120948152939091529091205461ffff16919050565b8060296000611b47611b96565b6001600160a01b03166001600160a01b03168152602001908152602001600020600084815260200190815260200160002060006101000a81548161ffff021916908361ffff1602179055505050565b6000303303611bec57600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b03169150611bef9050565b50335b90565b6000602781611bff611b96565b6001600160a01b031681526020808201929092526040908101600090812061ffff9586168252909252902054600160b01b9004909116919050565b8060276000611c47611b96565b6001600160a01b031681526020808201929092526040908101600090812061ffff96871682529092529020805491909316600160b01b0261ffff60b01b199091161790915550565b805182516000916001600160a01b03918216911614611cb057506000611d6c565b8251602084015160405163453bcd7d60e11b815260048101919091526000916001600160a01b031690638a779afa90602401602060405180830381865afa158015611cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d239190613914565b90508061ffff16836020015161ffff1603611d42576001915050611d6c565b602083015160ff16158015611d6857506020830151600890811c60ff9081169183901c16145b9150505b92915050565b6000828152601160209081526040808320815160608101835290546001600160a01b03811680835263ffffffff600160a01b83048116848701819052600160c01b90930416838501819052818752602b8652848720838852865284872061ffff89168852909552929094205491939291600191905b8260060160020a8110611dff57600190920191611de7565b50506000190192959194509250565b835161ffff16600090815260246020908152604080832080548251818502810185019093528083529192909190849084015b82821015611ec65760008481526020908190206040805160c08101825260028602909201805461ffff8082168552620100008204168486015263ffffffff6401000000008204169284019290925260ff600160401b830481166060850152600160481b909204909116608083015260019081015460a08301529083529092019101611e40565b5050505090506000611eda82868686612568565b905060005b815181101561212e576020808801516001600160a01b0316600090815260299091526040812083518290859085908110611f1b57611f1b613310565b6020908102919091018101515161ffff908116835290820192909252604001600020541690508015611fe157828281518110611f5957611f59613310565b60200260200101516020015181611f709190613931565b6020808a01516001600160a01b031660009081526029909152604081208551909190869086908110611fa457611fa4613310565b60200260200101516000015161ffff16815260200190815260200160002060006101000a81548161ffff021916908361ffff160217905550612125565b828281518110611ff357611ff3613310565b60200260200101516020015161ffff16600014612125576020808901516001600160a01b03166000908152602a90915260409020835184908490811061203b5761203b613310565b60200260200101516000015190806001815401808255809150506001900390600052602060002090601091828204019190066002029091909190916101000a81548161ffff021916908361ffff1602179055508282815181106120a0576120a0613310565b602002602001015160200151600060290160008a602001516001600160a01b03166001600160a01b0316815260200190815260200160002060008585815181106120ec576120ec613310565b60200260200101516000015161ffff16815260200190815260200160002060006101000a81548161ffff021916908361ffff1602179055505b50600101611edf565b50505050505050565b835161ffff16600090815260236020908152604080832080548251818502810185019093528083529192909190849084015b828210156122055760008481526020908190206040805160e0810182526002860290920180546001600160a01b0381168452600160a01b810461ffff90811685870152600160b01b8204811693850193909352600160c01b810463ffffffff166060850152600160e01b81049092166080840152600160f01b90910460ff1660a083015260019081015460c08301529083529092019101612169565b50505050905060006122198286868661273c565b905060005b815181101561212e576020808801516001600160a01b031660009081526027909152604081208351829085908590811061225a5761225a613310565b60209081029190910181015181015161ffff9081168352828201939093526040918201600020825160608101845290546001600160a01b0381168252600160a01b8104851692820192909252600160b01b90910490921690820181905290915015612364578282815181106122d1576122d1613310565b60200260200101516040015181604001516122ec9190613931565b6020808a01516001600160a01b03166000908152602790915260408120855190919086908690811061232057612320613310565b60200260200101516020015161ffff1661ffff16815260200190815260200160002060000160166101000a81548161ffff021916908361ffff1602179055506124db565b82828151811061237657612376613310565b60200260200101516040015161ffff166000146124db576020808901516001600160a01b0316600090815260289091526040902083518490849081106123be576123be613310565b60200260200101516020015190806001815401808255809150506001900390600052602060002090601091828204019190066002029091909190916101000a81548161ffff021916908361ffff16021790555082828151811061242357612423613310565b6020026020010151600060270160008a602001516001600160a01b03166001600160a01b03168152602001908152602001600020600085858151811061246b5761246b613310565b60209081029190910181015181015161ffff9081168352828201939093526040918201600020845181549286015195909301518416600160b01b0261ffff60b01b1995909416600160a01b026001600160b01b03199092166001600160a01b039093169290921717929092161790555b5060010161221e565b600080805b835181101561252b5780600a0285901c6103ff1684828151811061250f5761250f613310565b60200260200101510261ffff16820191508060010190506124e9565b5063ffffffff85166103e8612540828461394c565b61254b90600a61394c565b6125559190613963565b61255f9190613901565b95945050505050565b606084516001600160401b0381111561258357612583612f5e565b6040519080825280602002602001820160405280156125c857816020015b60408051808201909152600080825260208201528152602001906001900390816125a15790505b5090506000805b86518110156127325760405180604001604052808883815181106125f5576125f5613310565b60200260200101516000015161ffff168152602001600061ffff1681525083828151811061262557612625613310565b602090810291909101015261263b81600261394c565b86901c604051602001612662918152685265736f757263657360b81b602082015260290190565b6040516020818303038152906040528051906020012060001c915061270387828151811061269257612692613310565b6020026020010151604001518883815181106126b0576126b0613310565b60200260200101516060015160ff168984815181106126d1576126d1613310565b602002602001015160a001518a85815181106126ef576126ef613310565b602002602001015160800151898988612932565b83828151811061271557612715613310565b60209081029190910181015161ffff9092169101526001016125cf565b5050949350505050565b606084516001600160401b0381111561275757612757612f5e565b6040519080825280602002602001820160405280156127a257816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816127755790505b5090506000805b86518110156127325760405180606001604052808883815181106127cf576127cf613310565b6020026020010151600001516001600160a01b031681526020018883815181106127fb576127fb613310565b60200260200101516020015161ffff168152602001600061ffff1681525083828151811061282b5761282b613310565b602090810291909101015261284181600261394c565b86901c604051602001612863918152634e46547360e01b602082015260240190565b6040516020818303038152906040528051906020012060001c915061290187828151811061289357612893613310565b6020026020010151606001518883815181106128b1576128b1613310565b6020026020010151608001518984815181106128cf576128cf613310565b602002602001015160c001518a85815181106128ed576128ed613310565b602002602001015160a00151898988612932565b83828151811061291357612913613310565b602090810291909101015161ffff9091166040909101526001016127a9565b600080612941878686896129a1565b61294f9061ffff168a6137b2565b63ffffffff16905060005b8861ffff168110156129935781620186a06011830286901c0610156129845760018301925061298b565b5050612996565b60010161295a565b50505b979650505050505050565b600080805b85518110156129e75780600a0287901c6103ff169150818682815181106129cf576129cf613310565b602002602001015102830192508060010190506129a6565b506129f860ff60028518168561394c565b612a029083613931565b9150612a118261ffff16612a1b565b9695505050505050565b60b581600160881b8110612a345760409190911b9060801c5b600160481b8110612a4a5760209190911b9060401c5b600160281b8110612a605760109190911b9060201c5b63010000008110612a765760089190911b9060101c5b62010000010260121c80820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c808204811115612ab95781045b919050565b6020808252825182820181905260009190848201906040850190845b81811015612af657835183529284019291840191600101612ada565b50909695505050505050565b60008083601f840112612b1457600080fd5b5081356001600160401b03811115612b2b57600080fd5b6020830191508360208260061b8501011115612b4657600080fd5b9250929050565b60008083601f840112612b5f57600080fd5b5081356001600160401b03811115612b7657600080fd5b60208301915083602060e083028501011115612b4657600080fd5b60008083601f840112612ba357600080fd5b5081356001600160401b03811115612bba57600080fd5b60208301915083602060c083028501011115612b4657600080fd5b600060c08284031215610f5157600080fd5b60008060008060008060008060006101408a8c031215612c0657600080fd5b89356001600160401b0380821115612c1d57600080fd5b818c0191508c601f830112612c3157600080fd5b813581811115612c4057600080fd5b8d6020606083028501011115612c5557600080fd5b60209283019b509950908b01359080821115612c7057600080fd5b612c7c8d838e01612b02565b909950975060408c0135915080821115612c9557600080fd5b612ca18d838e01612b4d565b909750955060608c0135915080821115612cba57600080fd5b50612cc78c828d01612b91565b9094509250612cdb90508b60808c01612bd5565b90509295985092959850929598565b600060208284031215612cfc57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015612d5957815180516001600160a01b031688528381015161ffff908116858a0152604091820151169088015260609096019590820190600101612d17565b509495945050505050565b600081518084526020808501945080840160005b83811015612d5957815180516001600160a01b031688528381015161ffff908116858a01526040808301518216908a015260608083015163ffffffff16908a01526080808301519091169089015260a08082015160ff169089015260c0908101519088015260e09096019590820190600101612d78565b600081518084526020808501945080840160005b83811015612d59578151805161ffff908116895284820151168489015260408082015163ffffffff169089015260608082015160ff908116918a01919091526080808301519091169089015260a0908101519088015260c09096019590820190600101612e03565b6101408082528651908201819052600090610160830190602090818a01845b82811015612eb9578151805161ffff908116875290850151168486015260409094019390830190600101612e8a565b50505083820390840152612ecd8188612d03565b90508281036040840152612ee18187612d64565b90508281036060840152612ef58186612def565b915050612a116080830184805115158252602081015163ffffffff808216602085015261ffff6040840151166040850152806060840151166060850152806080840151166080850152505060a081015160a08301525050565b61ffff8116811461104157600080fd5b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612f9657612f96612f5e565b60405290565b604051601f8201601f191681016001600160401b0381118282101715612fc457612fc4612f5e565b604052919050565b60006001600160401b03821115612fe557612fe5612f5e565b5060051b60200190565b6001600160a01b038116811461104157600080fd5b60008060006060848603121561301957600080fd5b8335925060208085013561302c81612f4e565b92506040858101356001600160401b0381111561304857600080fd5b8601601f8101881361305957600080fd5b803561306c61306782612fcc565b612f9c565b81815260069190911b8201840190848101908a83111561308b57600080fd5b928501925b828410156130d45784848c0312156130a85760008081fd5b6130b0612f74565b84356130bb81612fef565b8152848701358782015282529284019290850190613090565b8096505050505050509250925092565b600080604083850312156130f757600080fd5b823591506020808401356001600160401b038082111561311657600080fd5b818601915086601f83011261312a57600080fd5b81358181111561313c5761313c612f5e565b61314e601f8201601f19168501612f9c565b9150808252878482850101111561316457600080fd5b80848401858401376000848284010152508093505050509250929050565b6000806040838503121561319557600080fd5b50508035926020909101359150565b801515811461104157600080fd5b600080604083850312156131c557600080fd5b8235915060208301356131d7816131a4565b809150509250929050565b600060208083850312156131f557600080fd5b82356001600160401b0381111561320b57600080fd5b8301601f8101851361321c57600080fd5b803561322a61306782612fcc565b81815260059190911b8201830190838101908783111561324957600080fd5b928401925b828410156129965783358252928401929084019061324e565b602080825282518282018190526000919060409081850190868401855b828110156132d4578151805161ffff168552868101516001600160a01b0316878601528581015163ffffffff90811687870152606091820151169085015260809093019290850190600101613284565b5091979650505050505050565b634e487b7160e01b600052601160045260246000fd5b600060018201613309576133096132e1565b5060010190565b634e487b7160e01b600052603260045260246000fd5b80546001600160a01b0319166001600160a01b0392909216919091179055565b805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b805461ffff60b01b191660b09290921b61ffff60b01b16919091179055565b813561338f81612fef565b6133998183613326565b5060208201356133a881612f4e565b6133b28183613346565b5060408201356133c181612f4e565b6133cb8183613365565b505050565b81356133db81612f4e565b815461ffff191661ffff82161782555060208201356133f981612f4e565b815463ffff00001916601082901b63ffff000016178255505050565b60006020828403121561342757600080fd5b813561343281612f4e565b9392505050565b6000813563ffffffff81168114611d6c57600080fd5b6000813560ff81168114611d6c57600080fd5b813561346d81612fef565b6134778183613326565b50602082013561348681612f4e565b6134908183613346565b50604082013561349f81612f4e565b6134a98183613365565b506134b660608301613439565b815463ffffffff60c01b19811660c09290921b63ffffffff60c01b16918217835560808401356134e581612f4e565b65ffffffffffff60c01b199190911690911760e09190911b61ffff60e01b1617815561353461351660a0840161344f565b82805460ff60f01b191660f09290921b60ff60f01b16919091179055565b60c082013560018201555050565b813561354d81612f4e565b815461ffff191661ffff821617825550602082013561356b81612f4e565b815463ffff00001916601082901b63ffff0000161782555061358f60408301613439565b815467ffffffff000000008260201b1691508167ffffffff0000000019821617835568ff00000000000000006135c76060860161344f565b60401b16808368ffffffffff000000001984161717845560ff60481b6135ef6080870161344f565b60481b168369ffffffffffff0000000019841617821717845550505060a082013560018201555050565b8135613624816131a4565b815460ff19811691151560ff16918217835564ffffffff0061364860208601613439565b60081b16808364ffffffffff19841617178455604085013561366981612f4e565b66ffff00000000008160281b168466ffffffffffffff198516178317178555505050506136c361369b60608401613439565b82546affffffff00000000000000191660389190911b6affffffff0000000000000016178255565b6136f66136d260808401613439565b82805463ffffffff60581b191660589290921b63ffffffff60581b16919091179055565b60a082013560018201555050565b60006020828403121561371657600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b038084168061374d5761374d61371d565b92169190910692915050565b6001600160401b03828116828216039080821115613779576137796132e1565b5092915050565b61ffff828116828216039080821115613779576137796132e1565b6000816137aa576137aa6132e1565b506000190190565b63ffffffff818116838216019080821115613779576137796132e1565b600060208083850312156137e257600080fd5b82516001600160401b03808211156137f957600080fd5b818501915085601f83011261380d57600080fd5b815161381b61306782612fcc565b81815260059190911b8301840190848101908883111561383a57600080fd5b938501935b8285101561386757845184811681146138585760008081fd5b8252938501939085019061383f565b98975050505050505050565b6000602080838503121561388657600080fd5b82516001600160401b0381111561389c57600080fd5b8301601f810185136138ad57600080fd5b80516138bb61306782612fcc565b81815260059190911b820183019083810190878311156138da57600080fd5b928401925b828410156129965783516138f281612f4e565b825292840192908401906138df565b80820180821115611d6c57611d6c6132e1565b60006020828403121561392657600080fd5b815161343281612f4e565b61ffff818116838216019080821115613779576137796132e1565b8082028115828204841417611d6c57611d6c6132e1565b6000826139725761397261371d565b50049056fea26469706673582212203407ac64ab3ebbfd29079904e3b641948fea38aa9a403dd28540099b9161429664736f6c63430008130033
Deployed Bytecode
0x6080604052600436106100915760003560e01c8063476343ee11610059578063476343ee1461015557806361b80af11461016a578063b68787371461017f578063bdcad3db1461019f578063f25747e0146101bf57600080fd5b806304c86e791461009657806308e50a2c146100c15780630fa1ecc3146100ef578063143a28e7146101205780632661bacf14610135575b600080fd5b3480156100a257600080fd5b506100ab6101ec565b6040516100b89190612abe565b60405180910390f35b3480156100cd57600080fd5b506100e16100dc366004612be7565b610247565b6040519081526020016100b8565b3480156100fb57600080fd5b5061010f61010a366004612cea565b6104c7565b6040516100b8959493929190612e6b565b61013361012e366004613004565b6107ed565b005b34801561014157600080fd5b506101336101503660046130e4565b6109e6565b34801561016157600080fd5b50610133610b8d565b34801561017657600080fd5b50610133610c45565b34801561018b57600080fd5b5061013361019a366004613182565b610c57565b3480156101ab57600080fd5b506101336101ba3660046131b2565b610dfd565b3480156101cb57600080fd5b506101df6101da3660046131e2565b610e25565b6040516100b89190613267565b60606000601f0180548060200260200160405190810160405280929190818152602001828054801561023d57602002820191906000526020600020905b815481526020019060010190808311610229575b5050505050905090565b6000610251610f57565b60208054906000610261836132f7565b91905055905060005b898110156102c85760008281526022602052604090208b8b8381811061029257610292613310565b835460018101855560009485526020909420606090910292909201929190910190506102be8282613384565b505060010161026a565b5060005b8781101561032a5760008281526021602052604090208989838181106102f4576102f4613310565b8354600181018555600094855260209094206040909102929092019291909101905061032082826133d0565b50506001016102cc565b5060005b858110156103dd57600d87878381811061034a5761034a613310565b905060e0020160800160208101906103629190613415565b61ffff16111561038557604051633cc4479360e11b815260040160405180910390fd5b60008281526023602052604090208787838181106103a5576103a5613310565b83546001810185556000948552602090942060e0909102929092019260020290910190506103d38282613462565b505060010161032e565b5060005b8381101561044157600082815260246020526040902085858381811061040957610409613310565b83546001810185556000948552602090942060c0909102929092019260020290910190506104378282613542565b50506001016103e1565b506000818152602560205260409020829061045c8282613619565b5050601f805460018101825560009182527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d8070182905560405182917fa110ffa8dafcbc1768f2a7031ffc4a4a62a3429ad91f3172c875ddeb637cd30591a29998505050505050505050565b6040805160c0810182526000808252602080830182905282840182905260608084018390526080840183905260a08401839052858352602182528483206022835285842060238452868520602485528786206025865288872084548a5181890281018901909b52808b5295998a998a998a999198889290919084015b82821015610586576000848152602090819020604080518082019091529084015461ffff8082168352620100009091041681830152825260019092019101610543565b50505050945083805480602002602001604051908101604052809291908181526020016000905b8282101561060557600084815260209081902060408051606081018252918501546001600160a01b038116835261ffff600160a01b8204811684860152600160b01b90910416908201528252600190920191016105ad565b50505050935082805480602002602001604051908101604052809291908181526020016000905b828210156106c85760008481526020908190206040805160e0810182526002860290920180546001600160a01b0381168452600160a01b810461ffff90811685870152600160b01b8204811693850193909352600160c01b810463ffffffff166060850152600160e01b81049092166080840152600160f01b90910460ff1660a083015260019081015460c0830152908352909201910161062c565b50505050925081805480602002602001604051908101604052809291908181526020016000905b828210156107755760008481526020908190206040805160c08101825260028602909201805461ffff8082168552620100008204168486015263ffffffff6401000000008204169284019290925260ff600160401b830481166060850152600160481b909204909116608083015260019081015460a083015290835290920191016106ef565b50506040805160c081018252855460ff81161515825263ffffffff61010082048116602084015261ffff600160281b83041693830193909352600160381b810483166060830152600160581b9004909116608082015260019094015460a085015250959c949b50929950919750909550909350505050565b60008381526008602052604081205484916001600160a01b03909116900361082857604051636aa2a93760e01b815260040160405180910390fd5b6000818152600860205260409020546001600160a01b0316331461085f5760405163daceb5e160e01b815260040160405180910390fd5b6000848152602660205260409020548490600160b01b900463ffffffff161561089b57604051635fd30cb160e01b815260040160405180910390fd5b60015460ff16156108bf576040516306d39fcd60e41b815260040160405180910390fd5b61ffff8085166000908152602560209081526040808320815160c081018352815460ff81161515825263ffffffff61010082048116958301869052600160281b820490971693820193909352600160381b830486166060820152600160581b909204909416608082015260019093015460a084015290036109535760405163b98b9c9f60e01b815260040160405180910390fd5b8051151560000361097757604051639d46cd6960e01b815260040160405180910390fd5b60195434146109985760405162a57da360e31b815260040160405180910390fd5b6109ac816080015163ffffffff1687611044565b6109b98561ffff1661108b565b6109c78561ffff16856112c1565b6109d6858783602001516115e2565b6109de61170f565b505050505050565b602e546001600160a01b03163314610a1157604051637b1fc71560e01b815260040160405180910390fd5b600081806020019051810190610a279190613704565b601d549091508190602c90600090610a52906102a090600160a01b90046001600160401b0316613733565b6001600160401b039081168252602082019290925260400160002091909155601d805467ffffffffffffffff60a01b198116600160a01b91829004841660010190931602919091179055601e548015610b255760008181526026602081815260408084208151608081018352815461ffff811682526001600160a01b03620100008204168286015263ffffffff600160b01b8204811694830194909452600160d01b90049092166060830152601e8590559385905291905281546001600160f01b031916909155610b23828261178f565b505b601d547f95095a68d304f692d102eb2d6bed743a6dfc02ff677525aba527e9666c39b99d90610b6690600190600160a01b90046001600160401b0316613759565b604080516001600160401b039092168252602082018590520160405180910390a150505050565b610b95610f57565b4715610bb45760405163774a4bd560e11b815260040160405180910390fd5b601d546001600160a01b0316610bdd57604051637c4ca5fd60e11b815260040160405180910390fd5b601d5460405147916000916001600160a01b039091169083908381818185875af1925050503d8060008114610c2e576040519150601f19603f3d011682016040523d82523d6000602084013e610c33565b606091505b5050905080610c4157600080fd5b5050565b610c4d610f57565b610c55611aa1565b565b60008281526008602052604081205483916001600160a01b039091169003610c9257604051636aa2a93760e01b815260040160405180910390fd5b6000818152600860205260409020546001600160a01b03163314610cc95760405163daceb5e160e01b815260040160405180910390fd5b6000838152602660209081526040918290208251608081018452905461ffff81168083526001600160a01b03620100008304169383019390935263ffffffff600160b01b8204811694830194909452600160d01b900490921660608301528314610d46576040516337ec0c6b60e11b815260040160405180910390fd5b43816040015163ffffffff161115610d715760405163a0da2a8160e01b815260040160405180910390fd5b6060810151601d5463ffffffff909116600160a01b9091046001600160401b03161115610dc357600084815260266020526040902080546001600160f01b0319169055610dbe848261178f565b610df7565b601e54600003610ddf57610dd5611aa1565b601e849055610df7565b60405162b419e560e01b815260040160405180910390fd5b50505050565b610e05610f57565b600091825260256020526040909120805460ff1916911515919091179055565b606081516001600160401b03811115610e4057610e40612f5e565b604051908082528060200260200182016040528015610e9257816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181610e5e5790505b50905060005b8251811015610f515760006026016000848381518110610eba57610eba613310565b60209081029190910181015182528181019290925260409081016000208151608081018352905461ffff811682526001600160a01b03620100008204169382019390935263ffffffff600160b01b8404811692820192909252600160d01b9092041660608201528251839083908110610f3557610f35613310565b602002602001018190525080610f4a906132f7565b9050610e98565b50919050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c1320547fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c906001600160a01b03163314801590610fc0575060038101546001600160a01b03163314155b15611041577fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f547fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c1320546040805162a87e2b60e41b81523360048201526001600160a01b03938416602482015291909216604482015290519081900360640190fd5b50565b81600003611050575050565b600081815260116020526040902054600160c01b900463ffffffff168214610c41576040516313205c1960e21b815260040160405180910390fd5b600081815260216020908152604080832080548251818502810185019093528083529192909190849084015b828210156110fa576000848152602090819020604080518082019091529084015461ffff80821683526201000090910416818301528252600190920191016110b7565b50505050905060008060005b83518110156112ba5761113984828151811061112457611124613310565b60200260200101516000015161ffff16611afb565b915083818151811061114d5761114d613310565b60200260200101516020015161ffff168261ffff16106111b6576111b184828151811061117c5761117c613310565b60200260200101516000015161ffff1685838151811061119e5761119e613310565b6020026020010151602001518403611b3a565b6112b2565b818482815181106111c9576111c9613310565b6020026020010151602001516111df9190613780565b61ffff1692506112118482815181106111fa576111fa613310565b60200260200101516000015161ffff166000611b3a565b6005546001600160a01b031663f5298aca61122a611b96565b86848151811061123c5761123c613310565b6020908102919091010151516040516001600160e01b031960e085901b1681526001600160a01b03909216600483015261ffff16602482015260448101869052606401600060405180830381600087803b15801561129957600080fd5b505af11580156112ad573d6000803e3d6000fd5b505050505b600101611106565b5050505050565b600082815260226020908152604080832080548251818502810185019093528083529192909190849084015b8282101561134557600084815260209081902060408051606081018252918501546001600160a01b038116835261ffff600160a01b8204811684860152600160b01b90910416908201528252600190920191016112ed565b505050509050600080805b83518110156109de5761137f84828151811061136e5761136e613310565b602002602001015160200151611bf2565b915083818151811061139357611393613310565b60200260200101516040015161ffff168261ffff16106113f8576113f38482815181106113c2576113c2613310565b6020026020010151602001518583815181106113e0576113e0613310565b6020026020010151604001518403611c3a565b6115da565b8184828151811061140b5761140b613310565b6020026020010151604001516114219190613780565b61ffff16925060276000611433611b96565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085838151811061146757611467613310565b60209081029190910181015181015161ffff16825281019190915260400160002080546001600160c01b031916905582156115bb5760005b85518110156115b9576114e48682815181106114bd576114bd613310565b60200260200101518684815181106114d7576114d7613310565b6020026020010151611c8f565b156115b1576114f28461379b565b935084828151811061150657611506613310565b6020026020010151600001516001600160a01b031663b390c0ab87838151811061153257611532613310565b60200260200101516020015160006040518363ffffffff1660e01b8152600401611566929190918252602082015260400190565b6020604051808303816000875af1158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a99190613704565b5083156115b9575b60010161149f565b505b82156115da57604051631f69f0e760e11b815260040160405180910390fd5b600101611350565b601d54600090611605906102a090600160a01b90046001600160401b0316613733565b9050600060405180608001604052808661ffff168152602001611626611b96565b6001600160a01b0316815260200161163e85436137b2565b63ffffffff908116825261ffff858116602093840181905260008981526026855260409081902086518154888801518985015160608b01518916600160d01b0263ffffffff60d01b1991909916600160b01b021667ffffffffffffffff60b01b196001600160a01b0390921662010000026001600160b01b0319909316938816939093179190911716179490941790935591519182529293509187169186917f1f8ac8b0980dabac3fd0ccee4885164cb997f4553e44e20cf8bfbeb789f150c5910160405180910390a35050505050565b60195460000361171b57565b602f546040516000916001600160a01b03169034908381818185875af1925050503d8060008114611768576040519150601f19603f3d011682016040523d82523d6000602084013e61176d565b606091505b505090508061104157604051630a6b029160e11b815260040160405180910390fd5b600080602c0160006102a0846060015163ffffffff166117af9190613733565b6001600160401b0316815260200190815260200160002054905060028110156117ea5760405162b419e560e01b815260040160405180910390fd5b604080516020810183905290810184905260600160408051601f198184030181528282528051602091820120855161ffff90811660009081526025845284812060c087018652805460ff81161515885263ffffffff6101008204811696890196909652600160281b8104909316958701869052600160381b830485166060880152600160581b90920490931660808601526001015460a0850152935090819081908190611898908990611d72565b93509350935093506060826001036119c457604051633940140f60e11b8152600481018590526000906001600160a01b03871690637280281e90602401600060405180830381865afa1580156118f2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261191a91908101906137cf565b9050856001600160a01b0316633600261d8260008151811061193e5761193e613310565b60209081029190910101516040516001600160e01b031960e084901b1681526001600160401b03909116600482015260016024820152604401600060405180830381865afa158015611994573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119bc9190810190613873565b9150506119e8565b60408051601980825261034082019092529060208201610320803683370190505090505b6119f488888385611e0e565b611a0088888385612137565b6000611a1587606001518860a00151846124e4565b6001600160a01b0387166000908152602b6020908152604080832089845282528083208b82015161ffff168452909152812080549293508392909190611a5c908490613901565b9091555050885160405161ffff909116908b907f93ec5673fed993d7e6454e9a6d078ea74b0622e3caed8fbe98c36f340ef718d390600090a350505050505050505050565b602d546040805163dea12bad60e01b815290516001600160a01b039092169163dea12bad9160048082019260009290919082900301818387803b158015611ae757600080fd5b505af1158015610df7573d6000803e3d6000fd5b6000602981611b08611b96565b6001600160a01b0316815260208082019290925260409081016000908120948152939091529091205461ffff16919050565b8060296000611b47611b96565b6001600160a01b03166001600160a01b03168152602001908152602001600020600084815260200190815260200160002060006101000a81548161ffff021916908361ffff1602179055505050565b6000303303611bec57600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b03169150611bef9050565b50335b90565b6000602781611bff611b96565b6001600160a01b031681526020808201929092526040908101600090812061ffff9586168252909252902054600160b01b9004909116919050565b8060276000611c47611b96565b6001600160a01b031681526020808201929092526040908101600090812061ffff96871682529092529020805491909316600160b01b0261ffff60b01b199091161790915550565b805182516000916001600160a01b03918216911614611cb057506000611d6c565b8251602084015160405163453bcd7d60e11b815260048101919091526000916001600160a01b031690638a779afa90602401602060405180830381865afa158015611cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d239190613914565b90508061ffff16836020015161ffff1603611d42576001915050611d6c565b602083015160ff16158015611d6857506020830151600890811c60ff9081169183901c16145b9150505b92915050565b6000828152601160209081526040808320815160608101835290546001600160a01b03811680835263ffffffff600160a01b83048116848701819052600160c01b90930416838501819052818752602b8652848720838852865284872061ffff89168852909552929094205491939291600191905b8260060160020a8110611dff57600190920191611de7565b50506000190192959194509250565b835161ffff16600090815260246020908152604080832080548251818502810185019093528083529192909190849084015b82821015611ec65760008481526020908190206040805160c08101825260028602909201805461ffff8082168552620100008204168486015263ffffffff6401000000008204169284019290925260ff600160401b830481166060850152600160481b909204909116608083015260019081015460a08301529083529092019101611e40565b5050505090506000611eda82868686612568565b905060005b815181101561212e576020808801516001600160a01b0316600090815260299091526040812083518290859085908110611f1b57611f1b613310565b6020908102919091018101515161ffff908116835290820192909252604001600020541690508015611fe157828281518110611f5957611f59613310565b60200260200101516020015181611f709190613931565b6020808a01516001600160a01b031660009081526029909152604081208551909190869086908110611fa457611fa4613310565b60200260200101516000015161ffff16815260200190815260200160002060006101000a81548161ffff021916908361ffff160217905550612125565b828281518110611ff357611ff3613310565b60200260200101516020015161ffff16600014612125576020808901516001600160a01b03166000908152602a90915260409020835184908490811061203b5761203b613310565b60200260200101516000015190806001815401808255809150506001900390600052602060002090601091828204019190066002029091909190916101000a81548161ffff021916908361ffff1602179055508282815181106120a0576120a0613310565b602002602001015160200151600060290160008a602001516001600160a01b03166001600160a01b0316815260200190815260200160002060008585815181106120ec576120ec613310565b60200260200101516000015161ffff16815260200190815260200160002060006101000a81548161ffff021916908361ffff1602179055505b50600101611edf565b50505050505050565b835161ffff16600090815260236020908152604080832080548251818502810185019093528083529192909190849084015b828210156122055760008481526020908190206040805160e0810182526002860290920180546001600160a01b0381168452600160a01b810461ffff90811685870152600160b01b8204811693850193909352600160c01b810463ffffffff166060850152600160e01b81049092166080840152600160f01b90910460ff1660a083015260019081015460c08301529083529092019101612169565b50505050905060006122198286868661273c565b905060005b815181101561212e576020808801516001600160a01b031660009081526027909152604081208351829085908590811061225a5761225a613310565b60209081029190910181015181015161ffff9081168352828201939093526040918201600020825160608101845290546001600160a01b0381168252600160a01b8104851692820192909252600160b01b90910490921690820181905290915015612364578282815181106122d1576122d1613310565b60200260200101516040015181604001516122ec9190613931565b6020808a01516001600160a01b03166000908152602790915260408120855190919086908690811061232057612320613310565b60200260200101516020015161ffff1661ffff16815260200190815260200160002060000160166101000a81548161ffff021916908361ffff1602179055506124db565b82828151811061237657612376613310565b60200260200101516040015161ffff166000146124db576020808901516001600160a01b0316600090815260289091526040902083518490849081106123be576123be613310565b60200260200101516020015190806001815401808255809150506001900390600052602060002090601091828204019190066002029091909190916101000a81548161ffff021916908361ffff16021790555082828151811061242357612423613310565b6020026020010151600060270160008a602001516001600160a01b03166001600160a01b03168152602001908152602001600020600085858151811061246b5761246b613310565b60209081029190910181015181015161ffff9081168352828201939093526040918201600020845181549286015195909301518416600160b01b0261ffff60b01b1995909416600160a01b026001600160b01b03199092166001600160a01b039093169290921717929092161790555b5060010161221e565b600080805b835181101561252b5780600a0285901c6103ff1684828151811061250f5761250f613310565b60200260200101510261ffff16820191508060010190506124e9565b5063ffffffff85166103e8612540828461394c565b61254b90600a61394c565b6125559190613963565b61255f9190613901565b95945050505050565b606084516001600160401b0381111561258357612583612f5e565b6040519080825280602002602001820160405280156125c857816020015b60408051808201909152600080825260208201528152602001906001900390816125a15790505b5090506000805b86518110156127325760405180604001604052808883815181106125f5576125f5613310565b60200260200101516000015161ffff168152602001600061ffff1681525083828151811061262557612625613310565b602090810291909101015261263b81600261394c565b86901c604051602001612662918152685265736f757263657360b81b602082015260290190565b6040516020818303038152906040528051906020012060001c915061270387828151811061269257612692613310565b6020026020010151604001518883815181106126b0576126b0613310565b60200260200101516060015160ff168984815181106126d1576126d1613310565b602002602001015160a001518a85815181106126ef576126ef613310565b602002602001015160800151898988612932565b83828151811061271557612715613310565b60209081029190910181015161ffff9092169101526001016125cf565b5050949350505050565b606084516001600160401b0381111561275757612757612f5e565b6040519080825280602002602001820160405280156127a257816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816127755790505b5090506000805b86518110156127325760405180606001604052808883815181106127cf576127cf613310565b6020026020010151600001516001600160a01b031681526020018883815181106127fb576127fb613310565b60200260200101516020015161ffff168152602001600061ffff1681525083828151811061282b5761282b613310565b602090810291909101015261284181600261394c565b86901c604051602001612863918152634e46547360e01b602082015260240190565b6040516020818303038152906040528051906020012060001c915061290187828151811061289357612893613310565b6020026020010151606001518883815181106128b1576128b1613310565b6020026020010151608001518984815181106128cf576128cf613310565b602002602001015160c001518a85815181106128ed576128ed613310565b602002602001015160a00151898988612932565b83828151811061291357612913613310565b602090810291909101015161ffff9091166040909101526001016127a9565b600080612941878686896129a1565b61294f9061ffff168a6137b2565b63ffffffff16905060005b8861ffff168110156129935781620186a06011830286901c0610156129845760018301925061298b565b5050612996565b60010161295a565b50505b979650505050505050565b600080805b85518110156129e75780600a0287901c6103ff169150818682815181106129cf576129cf613310565b602002602001015102830192508060010190506129a6565b506129f860ff60028518168561394c565b612a029083613931565b9150612a118261ffff16612a1b565b9695505050505050565b60b581600160881b8110612a345760409190911b9060801c5b600160481b8110612a4a5760209190911b9060401c5b600160281b8110612a605760109190911b9060201c5b63010000008110612a765760089190911b9060101c5b62010000010260121c80820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c808204811115612ab95781045b919050565b6020808252825182820181905260009190848201906040850190845b81811015612af657835183529284019291840191600101612ada565b50909695505050505050565b60008083601f840112612b1457600080fd5b5081356001600160401b03811115612b2b57600080fd5b6020830191508360208260061b8501011115612b4657600080fd5b9250929050565b60008083601f840112612b5f57600080fd5b5081356001600160401b03811115612b7657600080fd5b60208301915083602060e083028501011115612b4657600080fd5b60008083601f840112612ba357600080fd5b5081356001600160401b03811115612bba57600080fd5b60208301915083602060c083028501011115612b4657600080fd5b600060c08284031215610f5157600080fd5b60008060008060008060008060006101408a8c031215612c0657600080fd5b89356001600160401b0380821115612c1d57600080fd5b818c0191508c601f830112612c3157600080fd5b813581811115612c4057600080fd5b8d6020606083028501011115612c5557600080fd5b60209283019b509950908b01359080821115612c7057600080fd5b612c7c8d838e01612b02565b909950975060408c0135915080821115612c9557600080fd5b612ca18d838e01612b4d565b909750955060608c0135915080821115612cba57600080fd5b50612cc78c828d01612b91565b9094509250612cdb90508b60808c01612bd5565b90509295985092959850929598565b600060208284031215612cfc57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015612d5957815180516001600160a01b031688528381015161ffff908116858a0152604091820151169088015260609096019590820190600101612d17565b509495945050505050565b600081518084526020808501945080840160005b83811015612d5957815180516001600160a01b031688528381015161ffff908116858a01526040808301518216908a015260608083015163ffffffff16908a01526080808301519091169089015260a08082015160ff169089015260c0908101519088015260e09096019590820190600101612d78565b600081518084526020808501945080840160005b83811015612d59578151805161ffff908116895284820151168489015260408082015163ffffffff169089015260608082015160ff908116918a01919091526080808301519091169089015260a0908101519088015260c09096019590820190600101612e03565b6101408082528651908201819052600090610160830190602090818a01845b82811015612eb9578151805161ffff908116875290850151168486015260409094019390830190600101612e8a565b50505083820390840152612ecd8188612d03565b90508281036040840152612ee18187612d64565b90508281036060840152612ef58186612def565b915050612a116080830184805115158252602081015163ffffffff808216602085015261ffff6040840151166040850152806060840151166060850152806080840151166080850152505060a081015160a08301525050565b61ffff8116811461104157600080fd5b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612f9657612f96612f5e565b60405290565b604051601f8201601f191681016001600160401b0381118282101715612fc457612fc4612f5e565b604052919050565b60006001600160401b03821115612fe557612fe5612f5e565b5060051b60200190565b6001600160a01b038116811461104157600080fd5b60008060006060848603121561301957600080fd5b8335925060208085013561302c81612f4e565b92506040858101356001600160401b0381111561304857600080fd5b8601601f8101881361305957600080fd5b803561306c61306782612fcc565b612f9c565b81815260069190911b8201840190848101908a83111561308b57600080fd5b928501925b828410156130d45784848c0312156130a85760008081fd5b6130b0612f74565b84356130bb81612fef565b8152848701358782015282529284019290850190613090565b8096505050505050509250925092565b600080604083850312156130f757600080fd5b823591506020808401356001600160401b038082111561311657600080fd5b818601915086601f83011261312a57600080fd5b81358181111561313c5761313c612f5e565b61314e601f8201601f19168501612f9c565b9150808252878482850101111561316457600080fd5b80848401858401376000848284010152508093505050509250929050565b6000806040838503121561319557600080fd5b50508035926020909101359150565b801515811461104157600080fd5b600080604083850312156131c557600080fd5b8235915060208301356131d7816131a4565b809150509250929050565b600060208083850312156131f557600080fd5b82356001600160401b0381111561320b57600080fd5b8301601f8101851361321c57600080fd5b803561322a61306782612fcc565b81815260059190911b8201830190838101908783111561324957600080fd5b928401925b828410156129965783358252928401929084019061324e565b602080825282518282018190526000919060409081850190868401855b828110156132d4578151805161ffff168552868101516001600160a01b0316878601528581015163ffffffff90811687870152606091820151169085015260809093019290850190600101613284565b5091979650505050505050565b634e487b7160e01b600052601160045260246000fd5b600060018201613309576133096132e1565b5060010190565b634e487b7160e01b600052603260045260246000fd5b80546001600160a01b0319166001600160a01b0392909216919091179055565b805461ffff60a01b191660a09290921b61ffff60a01b16919091179055565b805461ffff60b01b191660b09290921b61ffff60b01b16919091179055565b813561338f81612fef565b6133998183613326565b5060208201356133a881612f4e565b6133b28183613346565b5060408201356133c181612f4e565b6133cb8183613365565b505050565b81356133db81612f4e565b815461ffff191661ffff82161782555060208201356133f981612f4e565b815463ffff00001916601082901b63ffff000016178255505050565b60006020828403121561342757600080fd5b813561343281612f4e565b9392505050565b6000813563ffffffff81168114611d6c57600080fd5b6000813560ff81168114611d6c57600080fd5b813561346d81612fef565b6134778183613326565b50602082013561348681612f4e565b6134908183613346565b50604082013561349f81612f4e565b6134a98183613365565b506134b660608301613439565b815463ffffffff60c01b19811660c09290921b63ffffffff60c01b16918217835560808401356134e581612f4e565b65ffffffffffff60c01b199190911690911760e09190911b61ffff60e01b1617815561353461351660a0840161344f565b82805460ff60f01b191660f09290921b60ff60f01b16919091179055565b60c082013560018201555050565b813561354d81612f4e565b815461ffff191661ffff821617825550602082013561356b81612f4e565b815463ffff00001916601082901b63ffff0000161782555061358f60408301613439565b815467ffffffff000000008260201b1691508167ffffffff0000000019821617835568ff00000000000000006135c76060860161344f565b60401b16808368ffffffffff000000001984161717845560ff60481b6135ef6080870161344f565b60481b168369ffffffffffff0000000019841617821717845550505060a082013560018201555050565b8135613624816131a4565b815460ff19811691151560ff16918217835564ffffffff0061364860208601613439565b60081b16808364ffffffffff19841617178455604085013561366981612f4e565b66ffff00000000008160281b168466ffffffffffffff198516178317178555505050506136c361369b60608401613439565b82546affffffff00000000000000191660389190911b6affffffff0000000000000016178255565b6136f66136d260808401613439565b82805463ffffffff60581b191660589290921b63ffffffff60581b16919091179055565b60a082013560018201555050565b60006020828403121561371657600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b038084168061374d5761374d61371d565b92169190910692915050565b6001600160401b03828116828216039080821115613779576137796132e1565b5092915050565b61ffff828116828216039080821115613779576137796132e1565b6000816137aa576137aa6132e1565b506000190190565b63ffffffff818116838216019080821115613779576137796132e1565b600060208083850312156137e257600080fd5b82516001600160401b03808211156137f957600080fd5b818501915085601f83011261380d57600080fd5b815161381b61306782612fcc565b81815260059190911b8301840190848101908883111561383a57600080fd5b938501935b8285101561386757845184811681146138585760008081fd5b8252938501939085019061383f565b98975050505050505050565b6000602080838503121561388657600080fd5b82516001600160401b0381111561389c57600080fd5b8301601f810185136138ad57600080fd5b80516138bb61306782612fcc565b81815260059190911b820183019083810190878311156138da57600080fd5b928401925b828410156129965783516138f281612f4e565b825292840192908401906138df565b80820180821115611d6c57611d6c6132e1565b60006020828403121561392657600080fd5b815161343281612f4e565b61ffff818116838216019080821115613779576137796132e1565b8082028115828204841417611d6c57611d6c6132e1565b6000826139725761397261371d565b50049056fea26469706673582212203407ac64ab3ebbfd29079904e3b641948fea38aa9a403dd28540099b9161429664736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in GLMR
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.