Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
GameCards
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {
ERC721AUpgradeable,
ERC721ABurnableUpgradeable
} from "@erc721a-upgradeable/extensions/ERC721ABurnableUpgradeable.sol";
import {
IERC721AUpgradeable,
IERC721ABurnableUpgradeable
} from "@erc721a-upgradeable/interfaces/IERC721ABurnableUpgradeable.sol";
import { OwnableRoles } from "@solady/src/auth/OwnableRoles.sol";
import { ECDSA } from "@solady/src/utils/ECDSA.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { AccessRoles } from "./access/AccessRoles.sol";
import { IGameCards } from "./interfaces/IGameCards.sol";
import { IBaseCards } from "./interfaces/IBaseCards.sol";
import { ISeeder } from "./interfaces/ISeeder.sol";
import { ICardAbilities } from "./interfaces/ICardAbilities.sol";
import { IMetadataRenderer } from "./interfaces/IMetadataRenderer.sol";
import { IBlast } from "./interfaces/IBlast.sol";
import { Game } from "./types/Game.sol";
/**
* @title GameCards
* @notice This contract handles all functionality related to tokenized game cards.
*/
contract GameCards is IGameCards, OwnableRoles, ERC721ABurnableUpgradeable, Initializable, UUPSUpgradeable {
using ECDSA for bytes32;
/// Bit packed stat variance values for each card tier.
uint256 private constant _STAT_VARIANCES = 0x640af253320aa333140a53220a0a44110a0a33110a0a2211;
uint256 private constant _WEIGHT_SUM = 10_000;
mapping(uint256 tokenId => Game.PlayerCard cards) private _playerCards;
mapping(uint256 level => Game.Stats modifiers) private _statModifiers;
mapping(uint256 baseCardId => uint256 serialNumber) public serialNumbers;
IBlast public immutable BLAST = IBlast(0x4300000000000000000000000000000000000002);
ISeeder public seeder;
IBaseCards public baseCards;
ICardAbilities public abilities;
IMetadataRenderer public metadataRenderer;
address public signer;
uint256 public maxCardLevel;
/**
* Disable initializers so that storage of the implementation cannot be modified.
*/
constructor() {
_disableInitializers();
}
/**
* @inheritdoc IGameCards
*/
function initialize(
address _owner,
address _gameMaster,
address _signer,
address _seeder,
address _baseCards,
address _abilities,
address _metadataRenderer,
address _blastGovernor
) initializerERC721A initializer external {
if (
_owner == address(0) ||
_gameMaster == address(0) ||
_signer == address(0) ||
_seeder == address(0) ||
_baseCards == address(0) ||
_abilities == address(0) ||
_metadataRenderer == address(0) ||
_blastGovernor == address(0)
) revert ZeroAddress();
BLAST.configureClaimableGas();
BLAST.configureGovernor({ _governor: _blastGovernor });
__ERC721A_init("Game Cards", "CARDS");
_initializeOwner({ newOwner: _owner });
_grantRoles({ user: _gameMaster, roles: AccessRoles.GAME_MASTER_ROLE });
signer = _signer;
maxCardLevel = 10;
seeder = ISeeder(_seeder);
baseCards = IBaseCards(_baseCards);
abilities = ICardAbilities(_abilities);
metadataRenderer = IMetadataRenderer(_metadataRenderer);
}
/**
* @inheritdoc IGameCards
*/
function mintCards(
uint256[] calldata cardIds,
uint256[6] calldata tierWeights,
address receiver
) external onlyRoles(AccessRoles.MINTER_ROLE) {
if (cardIds.length == 0) revert ZeroLengthArray();
if (receiver == address(0)) revert ZeroAddress();
_rollCardMetadata(cardIds, tierWeights);
_mint({ to: receiver, quantity: cardIds.length });
}
/**
* @inheritdoc IGameCards
*/
function incinerate(uint256[] calldata tokenIds) external onlyRoles(AccessRoles.MINTER_ROLE) {
if (tokenIds.length == 0) revert ZeroLengthArray();
for (uint256 i = 0; i < tokenIds.length; i++) {
_burn({ tokenId: tokenIds[i], approvalCheck: false });
}
}
/**
* @inheritdoc IGameCards
*/
function levelUpCard(uint256 tokenId, uint256 newLevel, bytes calldata signature) external {
if (!_exists(tokenId)) revert NonExistentTokenId();
if (msg.sender != ownerOf(tokenId)) revert CallerNotOwner();
if (newLevel > maxCardLevel) revert InvalidCardLevel();
uint256 cardLevel = ++_playerCards[tokenId].level;
if (cardLevel != newLevel) revert CardLevelMismatch();
bytes32 digest = keccak256(abi.encodePacked(tokenId, newLevel)).toEthSignedMessageHash();
if (digest.recover(signature) != signer) revert SignerMismatch();
emit LevelUp({ tokenId: tokenId, oldLevel: cardLevel - 1, newLevel: cardLevel });
}
/**
* @inheritdoc IGameCards
*/
function setSeeder(address newSeeder) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newSeeder == address(0)) revert ZeroAddress();
address oldSeeder = address(seeder);
seeder = ISeeder(newSeeder);
emit SeederUpdated(oldSeeder, newSeeder);
}
/**
* @inheritdoc IGameCards
*/
function setBaseCards(address newBaseCards) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newBaseCards == address(0)) revert ZeroAddress();
address oldBaseCards = address(baseCards);
baseCards = IBaseCards(newBaseCards);
emit BaseCardsUpdated(oldBaseCards, newBaseCards);
}
/**
* @inheritdoc IGameCards
*/
function setAbilities(address newAbilities) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newAbilities == address(0)) revert ZeroAddress();
address oldAbilities = address(abilities);
abilities = ICardAbilities(newAbilities);
emit AbilitiesUpdated(oldAbilities, newAbilities);
}
/**
* @inheritdoc IGameCards
*/
function setMetadataRenderer(address newMetadataRenderer) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newMetadataRenderer == address(0)) revert ZeroAddress();
address oldMetadataRenderer = address(metadataRenderer);
metadataRenderer = IMetadataRenderer(newMetadataRenderer);
emit MetadataRendererUpdated(oldMetadataRenderer, newMetadataRenderer);
}
/**
* @inheritdoc IGameCards
*/
function setSigner(address newSigner) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newSigner == address(0)) revert ZeroAddress();
address oldSigner = signer;
signer = newSigner;
emit SignerUpdated(oldSigner, newSigner);
}
/**
* @inheritdoc IGameCards
*/
function setCardLevelModifiers(uint256 level, Game.Stats calldata modifiers) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (level <= 1 || level > maxCardLevel) revert InvalidCardLevel();
Game.Stats memory oldModifiers = _statModifiers[level];
_statModifiers[level] = modifiers;
emit StatModifiersUpdated({ level: level, oldStatModifiers: oldModifiers, newStatModifiers: modifiers });
}
/**
* @inheritdoc IGameCards
*/
function setMaxCardLevel(uint256 newMaxLevel) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newMaxLevel == 0) revert InvalidMaxLevel();
uint256 oldMaxLevel = maxCardLevel;
maxCardLevel = newMaxLevel;
emit MaxCardLevelUpdated(oldMaxLevel, newMaxLevel);
}
/**
* @inheritdoc IGameCards
*/
function playerCards(uint256 tokenId) external view returns (Game.PlayerCard memory) {
if (!_exists(tokenId)) revert NonExistentTokenId();
Game.PlayerCard memory playerCard = _playerCards[tokenId];
playerCard = _updateCardStats(playerCard);
return playerCard;
}
/**
* @inheritdoc IGameCards
*/
function statModifiers(uint256 cardLevel) external view returns (Game.Stats memory) {
if (cardLevel == 0 || cardLevel > maxCardLevel) revert InvalidMaxLevel();
return _statModifiers[cardLevel];
}
/**
* Overrides the tokenURI function to render metadata on-chain.
*/
function tokenURI(uint256 tokenId) public view override(ERC721AUpgradeable, IERC721AUpgradeable) returns (string memory) {
if (!_exists(tokenId)) revert NonExistentTokenId();
Game.PlayerCard memory playerCard = _playerCards[tokenId];
playerCard = _updateCardStats(playerCard);
Game.BaseCard memory baseCard = baseCards.baseCards(playerCard.baseCardId);
return metadataRenderer.getMetadata(tokenId, playerCard, baseCard);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to roll card metadata.
* @param cardIds Array of card IDs to roll for.
* @param tierWeights Weightings associated with rolling a certain tier of card.
*/
function _rollCardMetadata(uint256[] calldata cardIds, uint256[6] calldata tierWeights) internal {
/// Query `seeder` for the current game seed.
uint256 ephemeralSeed = seeder.getAndUpdateGameSeed();
uint256 tokenId = _nextTokenId();
/// Iterate over each card ID.
for (uint256 i = 0; i < cardIds.length; i++) {
uint256 nextTokenId = tokenId + i;
uint256 cardId = cardIds[i];
Game.BaseCard memory baseCard = baseCards.baseCards({ baseCardId: cardId });
/// Define variables that can vary between card types.
Game.CardTier cardTier;
Game.Stats memory stats;
uint256[3] memory chosenAbilities;
/// If the base card is an artifact.
if (baseCard.cardType == Game.CardType.ARTIFACT) {
cardTier = baseCard.cardTier;
stats = Game.Stats(0, 0, 0, 0);
} else {
cardTier = _rollCardTier(ephemeralSeed, tierWeights);
stats = _rollStats({ cardTier: cardTier, baseStats: baseCard.stats, seed: ephemeralSeed });
chosenAbilities = abilities.getCardAbilities(cardTier, baseCard.archetypes, ephemeralSeed);
}
Game.PlayerCard memory playerCard = Game.PlayerCard({
baseCardId: cardId,
serialNumber: ++serialNumbers[cardId],
level: 1,
cardType: baseCard.cardType,
cardTier: cardTier,
unitType: baseCard.unitType,
stats: stats,
archetypes: baseCard.archetypes,
abilityIds: chosenAbilities
});
_playerCards[nextTokenId] = playerCard;
emit PlayerCardDefined({ tokenId: nextTokenId, newPlayerCard: playerCard });
// Reroll the ephemeral seed.
ephemeralSeed = uint256(keccak256(abi.encodePacked(ephemeralSeed)));
}
}
/**
* Function used to roll the tier of a card.
* @param seed Value used to derive a card tier.
* @param tierWeights Weightings associated with rolling a certain tier of card.
*/
function _rollCardTier(uint256 seed, uint256[6] calldata tierWeights) internal pure returns (Game.CardTier chosenTier) {
uint256 tierRoll = (seed % _WEIGHT_SUM) + 1;
uint256 cumulativeWeight = 0;
for (uint256 i = 0; i < tierWeights.length; i++) {
cumulativeWeight += tierWeights[i];
if (tierRoll <= cumulativeWeight) {
chosenTier = Game.CardTier(i+1);
break;
}
}
}
/**
* Function used to roll tokenized card stats.
* @param cardTier Tier of the card being rolled for.
* @param baseStats Base stats of the underlying base card.
* @param seed Value used to derive card stats.
*/
function _rollStats(
Game.CardTier cardTier,
Game.Stats memory baseStats,
uint256 seed
) internal pure returns (Game.Stats memory cardStats) {
uint256 variances = _STAT_VARIANCES >> (uint256(cardTier) - 1) * 32;
/// Roll HP.
bool debuff = seed & 1 == 0;
uint256 range = debuff ? variances >> 16 : variances >> 24;
uint256 roll = (seed % (range & 0xFF)) + 1;
cardStats.HP = debuff ? baseStats.HP - roll : baseStats.HP + roll;
/// Roll PWR.
debuff = seed >> 1 & 1 == 0;
range = debuff ? variances >> 8 : variances >> 12;
roll = (seed % (range & 0xF)) + 1;
cardStats.PWR = debuff ? baseStats.PWR - roll : baseStats.PWR + roll;
/// Roll DEF.
debuff = seed >> 2 & 1 == 0;
range = debuff ? variances >> 8 : variances >> 12;
roll = (seed % (range & 0xF)) + 1;
cardStats.DEF = debuff ? baseStats.DEF - roll : baseStats.DEF + roll;
/// Roll SPD.
debuff = seed >> 3 & 1 == 0;
range = debuff ? variances : variances >> 4;
roll = (seed % (range & 0xF)) + 1;
cardStats.SPD = debuff ? baseStats.SPD - roll : baseStats.SPD + roll;
}
function _updateCardStats(Game.PlayerCard memory playerCard) internal view returns (Game.PlayerCard memory) {
Game.Stats memory statMods = _statModifiers[playerCard.level];
playerCard.stats.HP += statMods.HP;
playerCard.stats.PWR += statMods.PWR;
playerCard.stats.DEF += statMods.DEF;
playerCard.stats.SPD += statMods.SPD;
playerCard.stats.SPD = playerCard.stats.SPD > 99 ? 99 : playerCard.stats.SPD;
return playerCard;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC721A OVERRIDES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Override the starting token ID to be 1.
*/
function _startTokenId() internal pure override returns (uint256) {
return 1;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* UUPSUPGRADEABLE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Overriden to ensure that only a Game Master can execute an upgrade.
*/
function _authorizeUpgrade(address newImplementation) internal override onlyRoles(AccessRoles.GAME_MASTER_ROLE) { }
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721ABurnableUpgradeable.sol';
import '../ERC721AUpgradeable.sol';
import '../ERC721A__Initializable.sol';
/**
* @title ERC721ABurnable.
*
* @dev ERC721A token that can be irreversibly burned (destroyed).
*/
abstract contract ERC721ABurnableUpgradeable is
ERC721A__Initializable,
ERC721AUpgradeable,
IERC721ABurnableUpgradeable
{
function __ERC721ABurnable_init() internal onlyInitializingERC721A {
__ERC721ABurnable_init_unchained();
}
function __ERC721ABurnable_init_unchained() internal onlyInitializingERC721A {}
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) public virtual override {
_burn(tokenId, true);
}
}// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../extensions/IERC721ABurnableUpgradeable.sol';
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Ownable} from "./Ownable.sol";
/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173)
/// for compatibility, the nomenclature for the 2-step ownership handover and roles
/// may be unique to this codebase.
abstract contract OwnableRoles is Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The `user`'s roles is updated to `roles`.
/// Each bit of `roles` represents whether the role is set.
event RolesUpdated(address indexed user, uint256 indexed roles);
/// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The role slot of `user` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
/// let roleSlot := keccak256(0x00, 0x20)
/// ```
/// This automatically ignores the upper bits of the `user` in case
/// they are not clean, as well as keep the `keccak256` under 32-bytes.
///
/// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`.
uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Overwrite the roles directly without authorization guard.
function _setRoles(address user, uint256 roles) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
// Store the new value.
sstore(keccak256(0x0c, 0x20), roles)
// Emit the {RolesUpdated} event.
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
}
}
/// @dev Updates the roles directly without authorization guard.
/// If `on` is true, each set bit of `roles` will be turned on,
/// otherwise, each set bit of `roles` will be turned off.
function _updateRoles(address user, uint256 roles, bool on) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
let roleSlot := keccak256(0x0c, 0x20)
// Load the current value.
let current := sload(roleSlot)
// Compute the updated roles if `on` is true.
let updated := or(current, roles)
// Compute the updated roles if `on` is false.
// Use `and` to compute the intersection of `current` and `roles`,
// `xor` it with `current` to flip the bits in the intersection.
if iszero(on) { updated := xor(current, and(current, roles)) }
// Then, store the new value.
sstore(roleSlot, updated)
// Emit the {RolesUpdated} event.
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
}
}
/// @dev Grants the roles directly without authorization guard.
/// Each bit of `roles` represents the role to turn on.
function _grantRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, true);
}
/// @dev Removes the roles directly without authorization guard.
/// Each bit of `roles` represents the role to turn off.
function _removeRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, false);
}
/// @dev Throws if the sender does not have any of the `roles`.
function _checkRoles(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Throws if the sender is not the owner,
/// and does not have any of the `roles`.
/// Checks for ownership first, then lazily checks for roles.
function _checkOwnerOrRoles(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner.
// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Throws if the sender does not have any of the `roles`,
/// and is not the owner.
/// Checks for roles first, then lazily checks for ownership.
function _checkRolesOrOwner(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
// If the caller is not the stored owner.
// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
/// @solidity memory-safe-assembly
assembly {
for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
// We don't need to mask the values of `ordinals`, as Solidity
// cleans dirty upper bits when storing variables into memory.
roles := or(shl(mload(add(ordinals, i)), 1), roles)
}
}
}
/// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
/// @solidity memory-safe-assembly
assembly {
// Grab the pointer to the free memory.
ordinals := mload(0x40)
let ptr := add(ordinals, 0x20)
let o := 0
// The absence of lookup tables, De Bruijn, etc., here is intentional for
// smaller bytecode, as this function is not meant to be called on-chain.
for { let t := roles } 1 {} {
mstore(ptr, o)
// `shr` 5 is equivalent to multiplying by 0x20.
// Push back into the ordinals array if the bit is set.
ptr := add(ptr, shl(5, and(t, 1)))
o := add(o, 1)
t := shr(o, roles)
if iszero(t) { break }
}
// Store the length of `ordinals`.
mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
// Allocate the memory.
mstore(0x40, ptr)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to grant `user` `roles`.
/// If the `user` already has a role, then it will be an no-op for the role.
function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
_grantRoles(user, roles);
}
/// @dev Allows the owner to remove `user` `roles`.
/// If the `user` does not have a role, then it will be an no-op for the role.
function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
_removeRoles(user, roles);
}
/// @dev Allow the caller to remove their own roles.
/// If the caller does not have a role, then it will be an no-op for the role.
function renounceRoles(uint256 roles) public payable virtual {
_removeRoles(msg.sender, roles);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the roles of `user`.
function rolesOf(address user) public view virtual returns (uint256 roles) {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
// Load the stored value.
roles := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Returns whether `user` has any of `roles`.
function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles != 0;
}
/// @dev Returns whether `user` has all of `roles`.
function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles == roles;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by an account with `roles`.
modifier onlyRoles(uint256 roles) virtual {
_checkRoles(roles);
_;
}
/// @dev Marks a function as only callable by the owner or by an account
/// with `roles`. Checks for ownership first, then lazily checks for roles.
modifier onlyOwnerOrRoles(uint256 roles) virtual {
_checkOwnerOrRoles(roles);
_;
}
/// @dev Marks a function as only callable by an account with `roles`
/// or the owner. Checks for roles first, then lazily checks for ownership.
modifier onlyRolesOrOwner(uint256 roles) virtual {
_checkRolesOrOwner(roles);
_;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ROLE CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// IYKYK
uint256 internal constant _ROLE_0 = 1 << 0;
uint256 internal constant _ROLE_1 = 1 << 1;
uint256 internal constant _ROLE_2 = 1 << 2;
uint256 internal constant _ROLE_3 = 1 << 3;
uint256 internal constant _ROLE_4 = 1 << 4;
uint256 internal constant _ROLE_5 = 1 << 5;
uint256 internal constant _ROLE_6 = 1 << 6;
uint256 internal constant _ROLE_7 = 1 << 7;
uint256 internal constant _ROLE_8 = 1 << 8;
uint256 internal constant _ROLE_9 = 1 << 9;
uint256 internal constant _ROLE_10 = 1 << 10;
uint256 internal constant _ROLE_11 = 1 << 11;
uint256 internal constant _ROLE_12 = 1 << 12;
uint256 internal constant _ROLE_13 = 1 << 13;
uint256 internal constant _ROLE_14 = 1 << 14;
uint256 internal constant _ROLE_15 = 1 << 15;
uint256 internal constant _ROLE_16 = 1 << 16;
uint256 internal constant _ROLE_17 = 1 << 17;
uint256 internal constant _ROLE_18 = 1 << 18;
uint256 internal constant _ROLE_19 = 1 << 19;
uint256 internal constant _ROLE_20 = 1 << 20;
uint256 internal constant _ROLE_21 = 1 << 21;
uint256 internal constant _ROLE_22 = 1 << 22;
uint256 internal constant _ROLE_23 = 1 << 23;
uint256 internal constant _ROLE_24 = 1 << 24;
uint256 internal constant _ROLE_25 = 1 << 25;
uint256 internal constant _ROLE_26 = 1 << 26;
uint256 internal constant _ROLE_27 = 1 << 27;
uint256 internal constant _ROLE_28 = 1 << 28;
uint256 internal constant _ROLE_29 = 1 << 29;
uint256 internal constant _ROLE_30 = 1 << 30;
uint256 internal constant _ROLE_31 = 1 << 31;
uint256 internal constant _ROLE_32 = 1 << 32;
uint256 internal constant _ROLE_33 = 1 << 33;
uint256 internal constant _ROLE_34 = 1 << 34;
uint256 internal constant _ROLE_35 = 1 << 35;
uint256 internal constant _ROLE_36 = 1 << 36;
uint256 internal constant _ROLE_37 = 1 << 37;
uint256 internal constant _ROLE_38 = 1 << 38;
uint256 internal constant _ROLE_39 = 1 << 39;
uint256 internal constant _ROLE_40 = 1 << 40;
uint256 internal constant _ROLE_41 = 1 << 41;
uint256 internal constant _ROLE_42 = 1 << 42;
uint256 internal constant _ROLE_43 = 1 << 43;
uint256 internal constant _ROLE_44 = 1 << 44;
uint256 internal constant _ROLE_45 = 1 << 45;
uint256 internal constant _ROLE_46 = 1 << 46;
uint256 internal constant _ROLE_47 = 1 << 47;
uint256 internal constant _ROLE_48 = 1 << 48;
uint256 internal constant _ROLE_49 = 1 << 49;
uint256 internal constant _ROLE_50 = 1 << 50;
uint256 internal constant _ROLE_51 = 1 << 51;
uint256 internal constant _ROLE_52 = 1 << 52;
uint256 internal constant _ROLE_53 = 1 << 53;
uint256 internal constant _ROLE_54 = 1 << 54;
uint256 internal constant _ROLE_55 = 1 << 55;
uint256 internal constant _ROLE_56 = 1 << 56;
uint256 internal constant _ROLE_57 = 1 << 57;
uint256 internal constant _ROLE_58 = 1 << 58;
uint256 internal constant _ROLE_59 = 1 << 59;
uint256 internal constant _ROLE_60 = 1 << 60;
uint256 internal constant _ROLE_61 = 1 << 61;
uint256 internal constant _ROLE_62 = 1 << 62;
uint256 internal constant _ROLE_63 = 1 << 63;
uint256 internal constant _ROLE_64 = 1 << 64;
uint256 internal constant _ROLE_65 = 1 << 65;
uint256 internal constant _ROLE_66 = 1 << 66;
uint256 internal constant _ROLE_67 = 1 << 67;
uint256 internal constant _ROLE_68 = 1 << 68;
uint256 internal constant _ROLE_69 = 1 << 69;
uint256 internal constant _ROLE_70 = 1 << 70;
uint256 internal constant _ROLE_71 = 1 << 71;
uint256 internal constant _ROLE_72 = 1 << 72;
uint256 internal constant _ROLE_73 = 1 << 73;
uint256 internal constant _ROLE_74 = 1 << 74;
uint256 internal constant _ROLE_75 = 1 << 75;
uint256 internal constant _ROLE_76 = 1 << 76;
uint256 internal constant _ROLE_77 = 1 << 77;
uint256 internal constant _ROLE_78 = 1 << 78;
uint256 internal constant _ROLE_79 = 1 << 79;
uint256 internal constant _ROLE_80 = 1 << 80;
uint256 internal constant _ROLE_81 = 1 << 81;
uint256 internal constant _ROLE_82 = 1 << 82;
uint256 internal constant _ROLE_83 = 1 << 83;
uint256 internal constant _ROLE_84 = 1 << 84;
uint256 internal constant _ROLE_85 = 1 << 85;
uint256 internal constant _ROLE_86 = 1 << 86;
uint256 internal constant _ROLE_87 = 1 << 87;
uint256 internal constant _ROLE_88 = 1 << 88;
uint256 internal constant _ROLE_89 = 1 << 89;
uint256 internal constant _ROLE_90 = 1 << 90;
uint256 internal constant _ROLE_91 = 1 << 91;
uint256 internal constant _ROLE_92 = 1 << 92;
uint256 internal constant _ROLE_93 = 1 << 93;
uint256 internal constant _ROLE_94 = 1 << 94;
uint256 internal constant _ROLE_95 = 1 << 95;
uint256 internal constant _ROLE_96 = 1 << 96;
uint256 internal constant _ROLE_97 = 1 << 97;
uint256 internal constant _ROLE_98 = 1 << 98;
uint256 internal constant _ROLE_99 = 1 << 99;
uint256 internal constant _ROLE_100 = 1 << 100;
uint256 internal constant _ROLE_101 = 1 << 101;
uint256 internal constant _ROLE_102 = 1 << 102;
uint256 internal constant _ROLE_103 = 1 << 103;
uint256 internal constant _ROLE_104 = 1 << 104;
uint256 internal constant _ROLE_105 = 1 << 105;
uint256 internal constant _ROLE_106 = 1 << 106;
uint256 internal constant _ROLE_107 = 1 << 107;
uint256 internal constant _ROLE_108 = 1 << 108;
uint256 internal constant _ROLE_109 = 1 << 109;
uint256 internal constant _ROLE_110 = 1 << 110;
uint256 internal constant _ROLE_111 = 1 << 111;
uint256 internal constant _ROLE_112 = 1 << 112;
uint256 internal constant _ROLE_113 = 1 << 113;
uint256 internal constant _ROLE_114 = 1 << 114;
uint256 internal constant _ROLE_115 = 1 << 115;
uint256 internal constant _ROLE_116 = 1 << 116;
uint256 internal constant _ROLE_117 = 1 << 117;
uint256 internal constant _ROLE_118 = 1 << 118;
uint256 internal constant _ROLE_119 = 1 << 119;
uint256 internal constant _ROLE_120 = 1 << 120;
uint256 internal constant _ROLE_121 = 1 << 121;
uint256 internal constant _ROLE_122 = 1 << 122;
uint256 internal constant _ROLE_123 = 1 << 123;
uint256 internal constant _ROLE_124 = 1 << 124;
uint256 internal constant _ROLE_125 = 1 << 125;
uint256 internal constant _ROLE_126 = 1 << 126;
uint256 internal constant _ROLE_127 = 1 << 127;
uint256 internal constant _ROLE_128 = 1 << 128;
uint256 internal constant _ROLE_129 = 1 << 129;
uint256 internal constant _ROLE_130 = 1 << 130;
uint256 internal constant _ROLE_131 = 1 << 131;
uint256 internal constant _ROLE_132 = 1 << 132;
uint256 internal constant _ROLE_133 = 1 << 133;
uint256 internal constant _ROLE_134 = 1 << 134;
uint256 internal constant _ROLE_135 = 1 << 135;
uint256 internal constant _ROLE_136 = 1 << 136;
uint256 internal constant _ROLE_137 = 1 << 137;
uint256 internal constant _ROLE_138 = 1 << 138;
uint256 internal constant _ROLE_139 = 1 << 139;
uint256 internal constant _ROLE_140 = 1 << 140;
uint256 internal constant _ROLE_141 = 1 << 141;
uint256 internal constant _ROLE_142 = 1 << 142;
uint256 internal constant _ROLE_143 = 1 << 143;
uint256 internal constant _ROLE_144 = 1 << 144;
uint256 internal constant _ROLE_145 = 1 << 145;
uint256 internal constant _ROLE_146 = 1 << 146;
uint256 internal constant _ROLE_147 = 1 << 147;
uint256 internal constant _ROLE_148 = 1 << 148;
uint256 internal constant _ROLE_149 = 1 << 149;
uint256 internal constant _ROLE_150 = 1 << 150;
uint256 internal constant _ROLE_151 = 1 << 151;
uint256 internal constant _ROLE_152 = 1 << 152;
uint256 internal constant _ROLE_153 = 1 << 153;
uint256 internal constant _ROLE_154 = 1 << 154;
uint256 internal constant _ROLE_155 = 1 << 155;
uint256 internal constant _ROLE_156 = 1 << 156;
uint256 internal constant _ROLE_157 = 1 << 157;
uint256 internal constant _ROLE_158 = 1 << 158;
uint256 internal constant _ROLE_159 = 1 << 159;
uint256 internal constant _ROLE_160 = 1 << 160;
uint256 internal constant _ROLE_161 = 1 << 161;
uint256 internal constant _ROLE_162 = 1 << 162;
uint256 internal constant _ROLE_163 = 1 << 163;
uint256 internal constant _ROLE_164 = 1 << 164;
uint256 internal constant _ROLE_165 = 1 << 165;
uint256 internal constant _ROLE_166 = 1 << 166;
uint256 internal constant _ROLE_167 = 1 << 167;
uint256 internal constant _ROLE_168 = 1 << 168;
uint256 internal constant _ROLE_169 = 1 << 169;
uint256 internal constant _ROLE_170 = 1 << 170;
uint256 internal constant _ROLE_171 = 1 << 171;
uint256 internal constant _ROLE_172 = 1 << 172;
uint256 internal constant _ROLE_173 = 1 << 173;
uint256 internal constant _ROLE_174 = 1 << 174;
uint256 internal constant _ROLE_175 = 1 << 175;
uint256 internal constant _ROLE_176 = 1 << 176;
uint256 internal constant _ROLE_177 = 1 << 177;
uint256 internal constant _ROLE_178 = 1 << 178;
uint256 internal constant _ROLE_179 = 1 << 179;
uint256 internal constant _ROLE_180 = 1 << 180;
uint256 internal constant _ROLE_181 = 1 << 181;
uint256 internal constant _ROLE_182 = 1 << 182;
uint256 internal constant _ROLE_183 = 1 << 183;
uint256 internal constant _ROLE_184 = 1 << 184;
uint256 internal constant _ROLE_185 = 1 << 185;
uint256 internal constant _ROLE_186 = 1 << 186;
uint256 internal constant _ROLE_187 = 1 << 187;
uint256 internal constant _ROLE_188 = 1 << 188;
uint256 internal constant _ROLE_189 = 1 << 189;
uint256 internal constant _ROLE_190 = 1 << 190;
uint256 internal constant _ROLE_191 = 1 << 191;
uint256 internal constant _ROLE_192 = 1 << 192;
uint256 internal constant _ROLE_193 = 1 << 193;
uint256 internal constant _ROLE_194 = 1 << 194;
uint256 internal constant _ROLE_195 = 1 << 195;
uint256 internal constant _ROLE_196 = 1 << 196;
uint256 internal constant _ROLE_197 = 1 << 197;
uint256 internal constant _ROLE_198 = 1 << 198;
uint256 internal constant _ROLE_199 = 1 << 199;
uint256 internal constant _ROLE_200 = 1 << 200;
uint256 internal constant _ROLE_201 = 1 << 201;
uint256 internal constant _ROLE_202 = 1 << 202;
uint256 internal constant _ROLE_203 = 1 << 203;
uint256 internal constant _ROLE_204 = 1 << 204;
uint256 internal constant _ROLE_205 = 1 << 205;
uint256 internal constant _ROLE_206 = 1 << 206;
uint256 internal constant _ROLE_207 = 1 << 207;
uint256 internal constant _ROLE_208 = 1 << 208;
uint256 internal constant _ROLE_209 = 1 << 209;
uint256 internal constant _ROLE_210 = 1 << 210;
uint256 internal constant _ROLE_211 = 1 << 211;
uint256 internal constant _ROLE_212 = 1 << 212;
uint256 internal constant _ROLE_213 = 1 << 213;
uint256 internal constant _ROLE_214 = 1 << 214;
uint256 internal constant _ROLE_215 = 1 << 215;
uint256 internal constant _ROLE_216 = 1 << 216;
uint256 internal constant _ROLE_217 = 1 << 217;
uint256 internal constant _ROLE_218 = 1 << 218;
uint256 internal constant _ROLE_219 = 1 << 219;
uint256 internal constant _ROLE_220 = 1 << 220;
uint256 internal constant _ROLE_221 = 1 << 221;
uint256 internal constant _ROLE_222 = 1 << 222;
uint256 internal constant _ROLE_223 = 1 << 223;
uint256 internal constant _ROLE_224 = 1 << 224;
uint256 internal constant _ROLE_225 = 1 << 225;
uint256 internal constant _ROLE_226 = 1 << 226;
uint256 internal constant _ROLE_227 = 1 << 227;
uint256 internal constant _ROLE_228 = 1 << 228;
uint256 internal constant _ROLE_229 = 1 << 229;
uint256 internal constant _ROLE_230 = 1 << 230;
uint256 internal constant _ROLE_231 = 1 << 231;
uint256 internal constant _ROLE_232 = 1 << 232;
uint256 internal constant _ROLE_233 = 1 << 233;
uint256 internal constant _ROLE_234 = 1 << 234;
uint256 internal constant _ROLE_235 = 1 << 235;
uint256 internal constant _ROLE_236 = 1 << 236;
uint256 internal constant _ROLE_237 = 1 << 237;
uint256 internal constant _ROLE_238 = 1 << 238;
uint256 internal constant _ROLE_239 = 1 << 239;
uint256 internal constant _ROLE_240 = 1 << 240;
uint256 internal constant _ROLE_241 = 1 << 241;
uint256 internal constant _ROLE_242 = 1 << 242;
uint256 internal constant _ROLE_243 = 1 << 243;
uint256 internal constant _ROLE_244 = 1 << 244;
uint256 internal constant _ROLE_245 = 1 << 245;
uint256 internal constant _ROLE_246 = 1 << 246;
uint256 internal constant _ROLE_247 = 1 << 247;
uint256 internal constant _ROLE_248 = 1 << 248;
uint256 internal constant _ROLE_249 = 1 << 249;
uint256 internal constant _ROLE_250 = 1 << 250;
uint256 internal constant _ROLE_251 = 1 << 251;
uint256 internal constant _ROLE_252 = 1 << 252;
uint256 internal constant _ROLE_253 = 1 << 253;
uint256 internal constant _ROLE_254 = 1 << 254;
uint256 internal constant _ROLE_255 = 1 << 255;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
/// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure.
/// This is for more safety by default.
/// Use the `tryRecover` variants if you need to get the zero address back
/// upon recovery failure instead.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
/// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
/// See: https://eips.ethereum.org/EIPS/eip-2098
/// This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT use signatures as unique identifiers:
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
/// EIP-712 also enables readable signing of typed data for better user safety.
/// This implementation does NOT check if a signature is non-malleable.
library ECDSA {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The signature is invalid.
error InvalidSignature();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RECOVERY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
for {} 1 {} {
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
if eq(mload(signature), 64) {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(mload(signature), 65) {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
break
}
result := 0
break
}
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
for {} 1 {} {
if eq(signature.length, 64) {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(signature.length, 65) {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
break
}
result := 0
break
}
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* TRY-RECOVER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// WARNING!
// These functions will NOT revert upon recovery failure.
// Instead, they will return the zero address upon recovery failure.
// It is critical that the returned address is NEVER compared against
// a zero address (e.g. an uninitialized address variable).
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecover(bytes32 hash, bytes memory signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
for {} 1 {} {
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
if eq(mload(signature), 64) {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(mload(signature), 65) {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
break
}
result := 0
break
}
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
for {} 1 {} {
if eq(signature.length, 64) {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(signature.length, 65) {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
break
}
result := 0
break
}
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an Ethereum Signed Message, created from a `hash`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
/// JSON-RPC method as part of EIP-191.
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, hash) // Store into scratch space for keccak256.
mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
}
}
/// @dev Returns an Ethereum Signed Message, created from `s`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
/// JSON-RPC method as part of EIP-191.
/// Note: Supports lengths of `s` up to 999999 bytes.
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let sLength := mload(s)
let o := 0x20
mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
mstore(0x00, 0x00)
// Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
for { let temp := sLength } 1 {} {
o := sub(o, 1)
mstore8(o, add(48, mod(temp, 10)))
temp := div(temp, 10)
if iszero(temp) { break }
}
let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
// Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
mstore(s, sLength) // Restore the length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes.
function emptySignature() internal pure returns (bytes calldata signature) {
/// @solidity memory-safe-assembly
assembly {
signature.length := 0
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/**
* @title AccessRoles
* @notice This library contains all the valid roles within the protocol. Roles have been defined to mimic
* {Solady.OwnableRoles} roles.
*/
library AccessRoles {
/// `OwnableRoles._ROLE_0`
uint256 public constant GAME_MASTER_ROLE = 1 << 0;
/// `OwnableRoles._ROLE_1`
uint256 public constant SEEDER_ROLE = 1 << 1;
/// `OwnableRoles._ROLE_2`
uint256 public constant MINTER_ROLE = 1 << 2;
/// `OwnableRoles._ROLE_3`
uint256 public constant RESOLVER_ROLE = 1 << 3;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import { ICardAbilities } from "./ICardAbilities.sol";
import { IERC721AUpgradeable } from "@erc721a-upgradeable/interfaces/IERC721AUpgradeable.sol";
import { Game } from "../types/Game.sol";
/**
* @title IGameCards
* @notice Interface for GameCards.
*/
interface IGameCards is IERC721AUpgradeable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided.
*/
error ZeroAddress();
/**
* Thrown when an input array of zero length is provided.
*/
error ZeroLengthArray();
/**
* Thrown when trying to access data for a non-existent token ID.
*/
error NonExistentTokenId();
/**
* Thrown when the caller is not the owner of the card.
*/
error CallerNotOwner();
/**
* Thrown when the specified level does not match the expected level.
*/
error CardLevelMismatch();
/**
* Thrown when the recovered signer does not match the expected signer.
*/
error SignerMismatch();
/**
* Thrown when an invalid card level is provided.
*/
error InvalidCardLevel();
/**
* Thrown when an invalid maximum card level is provided.
*/
error InvalidMaxLevel();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when a new player card is defined.
* @param tokenId Unique token identifier.
* @param newPlayerCard Information relating to the newly defined player card.
*/
event PlayerCardDefined(uint256 indexed tokenId, Game.PlayerCard newPlayerCard);
/**
* Emitted when the `Seeder` contract is updated.
* @param oldSeeder Old `Seeder` contract address.
* @param newSeeder New `Seeder` contract address.
*/
event SeederUpdated(address oldSeeder, address newSeeder);
/**
* Emitted when the `Abilities` contract is updated.
* @param oldAbilities Old `Abilities` contract address.
* @param newAbilities New `Abilities` contract address.
*/
event AbilitiesUpdated(address oldAbilities, address newAbilities);
/**
* Emitted when the `MetadataRenderer` contract is updated.
* @param oldMetadataRenderer Old `MetadataRenderer` contract address.
* @param newMetadataRenderer New `MetadataRenderer` contract address.
*/
event MetadataRendererUpdated(address oldMetadataRenderer, address newMetadataRenderer);
/**
* Emitted when the `signer` address is updated.
* @param oldSigner Old `signer` address.
* @param newSigner New `signer` address.
*/
event SignerUpdated(address indexed oldSigner, address indexed newSigner);
/**
* Emitted when the `baseCards` address is updated.
* @param oldBaseCards Old `baseCards` address.
* @param newBaseCards New `baseCards` address.
*/
event BaseCardsUpdated(address oldBaseCards, address newBaseCards);
/**
* Emitted when a player card is leveled.
* @param tokenId Unique card identifier.
* @param oldLevel Old card level.
* @param newLevel New card level.
*/
event LevelUp(uint256 indexed tokenId, uint256 oldLevel, uint256 newLevel);
/**
* Emitted when the maximum card level is updated.
* @param oldMaxLevel Old maximum card level.
* @param newMaxLevel New maximum card level.
*/
event MaxCardLevelUpdated(uint256 oldMaxLevel, uint256 newMaxLevel);
/**
* Emitted when level stat modifiers are updated.
* @param level Stat level being modified.
* @param oldStatModifiers Old stat modifiers for `level`.
* @param newStatModifiers New stat modifiers for `level`.
*/
event StatModifiersUpdated(uint256 indexed level, Game.Stats oldStatModifiers, Game.Stats newStatModifiers);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to view the total number of derivative base cards that have been minted.
* @param baseCardId Unique base card identifier.
*/
function serialNumbers(uint256 baseCardId) external view returns (uint256);
/**
* Function used to initialize the Cards contract.
* @param _owner Contract owner.
* @param _gameMaster Designed Game Master.
* @param _signer Signer address.
* @param _seeder Seeder contract.
* @param _baseCards BaseCards contract.
* @param _abilities Abilities contract.
* @param _metadataRenderer Metadata renderer contract.
* @param _blastGovernor Blast Governor contract.
*/
function initialize(
address _owner,
address _gameMaster,
address _signer,
address _seeder,
address _baseCards,
address _abilities,
address _metadataRenderer,
address _blastGovernor
) external;
/**
* Function used to mint new cards to the receiver.
* @param cardIds Unique card identifiers to mint.
* @param tierWeights Weightings associated with rolling a specific tier of card.
* @param receiver Address to mint the new cards to.
*/
function mintCards(uint256[] calldata cardIds, uint256[6] calldata tierWeights, address receiver) external;
/**
* Function used to incinerate a list of cards.
* @param tokenIds Array of card identifiers.
*/
function incinerate(uint256[] calldata tokenIds) external;
/**
* Function used to level up a card.
* @param tokenId Unique card identifier.
* @param newLevel Expected new level of the card.
* @param signature Signed message digest.
*/
function levelUpCard(uint256 tokenId, uint256 newLevel, bytes calldata signature) external;
/**
* Function used to set a new `Seeder` value.
* @param newSeeder New `Seeder` contract address.
*/
function setSeeder(address newSeeder) external;
/**
* Function used to set a new `BaseCards` value.
* @param newBaseCards New `BaseCards` contract address.
*/
function setBaseCards(address newBaseCards) external;
/**
* Function used to set a new `Abilities` value.
* @param newAbilities New `Abilities` contract address.
*/
function setAbilities(address newAbilities) external;
/**
* Function used to set a new `MetadataRenderer` value.
* @param newMetadataRenderer New `MetadataRenderer` contract address.
*/
function setMetadataRenderer(address newMetadataRenderer) external;
/**
* Function used to set a new `signer` address.
* @param newSigner New `signer` address value.
*/
function setSigner(address newSigner) external;
/**
* Function used to set stat modifiers for a specified card level.
* @param level Card level to set stat modifiers for.
* @param modifiers New stat modifiers for `level`.
*/
function setCardLevelModifiers(uint256 level, Game.Stats calldata modifiers) external;
/**
* Function used to set a new maximum card level.
* @param newMaxLevel New maximum card level value.
*/
function setMaxCardLevel(uint256 newMaxLevel) external;
/**
* Function used to view the `Game.PlayerCard` struct for a given token idenitifer.
* @param tokenId Unique token identifier.
*/
function playerCards(uint256 tokenId) external view returns (Game.PlayerCard memory);
/**
* Function used to view the current stat modifiers of a given card level.
* @param cardLevel Card level to check modifiers for.
*/
function statModifiers(uint256 cardLevel) external view returns (Game.Stats memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import { Game } from "../types/Game.sol";
/**
* @title IBaseCards
* @notice Interface for BaseCards.
*/
interface IBaseCards {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided as input.
*/
error ZeroAddress();
/**
* Thrown when an input array of zero length is provided.
*/
error ZeroLengthArray();
/**
* Thrown when invalid card attributes have been provided.
*/
error InvalidCardStats();
/**
* Thrown when an undefined Game.Unit type is provided.
*/
error UndefinedUnitType();
/**
* Thrown when an undefined archetype type is provided.
*/
error UndefinedArchetype();
/**
* Thrown when an invalid card ID is provided.
*/
error InvalidCardId();
/**
* Thrown when a duplicate archetype value is provided when adding base cards.
*/
error DuplicateArchetype();
/**
* Thrown when an undefined card type is provided when editing a base card.
*/
error UndefinedCardType();
/**
* Thrown when an invalid card tier is provided when editing a base card.
*/
error InvalidCardTier();
/**
* Thrown when a zero length name is provided when editing a base card.
*/
error EmptyName();
/**
* Thrown when a zero length image URI is provided when editing a base card.
*/
error EmptyImageURI();
/**
* Thrown when a unit card has invalid stats.
*/
error InvalidUnitStats();
/**
* Thrown when an undefined card tier is provided.
*/
error UndefinedCardTier();
/**
* Thrown when no name or image URI are provided when editing a card.
*/
error EmptyParameters();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when a new base card is added to the game.
* @param baseCardId Unique base card identifier.
* @param newBaseCard Information relating to the newly added base card.
*/
event BaseCardAdded(uint256 indexed baseCardId, Game.BaseCard newBaseCard);
/**
* Emitted when a base card is modified.
* @param baseCardId Unique base card identifier.
* @param oldBaseCard Old `Game.BaseCard` struct.
* @param newBaseCard New `Game.BaseCard` struct.
*/
event BaseCardUpdated(uint256 indexed baseCardId, Game.BaseCard oldBaseCard, Game.BaseCard newBaseCard);
/**
* Emitted when the image URI of a base card is modified.
* @param baseCardId Unique base card identifier.
* @param oldImageURI Old `imageURI` value.
* @param newImageURI New `imageURI` value.
*/
event BaseCardImageURIUpdated(uint256 indexed baseCardId, string oldImageURI, string newImageURI);
/**
* Emitted when the `Game.BaseCard.name` value is modified.
* @param baseCardId Unique base card identifier.
* @param oldName Old `Game.BaseCard.name` value.
* @param newName New `Game.BaseCard.name` value.
*/
event BaseCardNameUpdated(uint256 indexed baseCardId, string oldName, string newName);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to view the total number of base cards.
*/
function baseCardCount() external view returns (uint256);
/**
* Function used to add new base cards to the game.
* @param units Array of unit base cards to add.
* @param artifacts Array of artifact base cards to add.
*/
function addBaseCards(Game.Unit[] calldata units, Game.Artifact[] calldata artifacts) external;
/**
* Function used to edit a base card.
* @param baseCardId Unique base card identifier.
* @param newBaseCard Newly desired `Game.BaseCard` struct.
* @dev This function may only be called if tokenized versions of this card have never been minted.
*/
function editBaseCard(uint256 baseCardId, Game.BaseCard calldata newBaseCard) external;
/**
* Function used to modify the image URI of a base card.
* @param baseCardId Unique base card identifier.
* @param newName Newly desired `name` value.
* @param newImageURI Newly desired `imageURI` value.
*/
function setNameAndImageURI(uint256 baseCardId, string calldata newName, string calldata newImageURI) external;
/**
* Function used to view the `Game.BaseCard` struct for a given card identifier.
* @param baseCardId Unique base card idenitifer.
*/
function baseCards(uint256 baseCardId) external view returns (Game.BaseCard memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/**
* @title ISeeder
* @notice Interface for Seeder.
*/
interface ISeeder {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided as input.
*/
error ZeroAddress();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when the game seed is updated.
* @param oldSeed Old game seed.
* @param newSeed New game seed.
*/
event GameSeedUpdated(uint256 oldSeed, uint256 newSeed);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to get the current game seed and update it. The value returned
* is the game seed prior to the update.
*/
function getAndUpdateGameSeed() external returns (uint256);
/**
* Function used to view the current game seed.
*/
function currentGameSeed() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import { Game } from "../types/Game.sol";
/**
* @title ICardAbilities
* @notice Interface for CardAbilities.
*/
interface ICardAbilities {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when a Ability input array of zero length is provided.
*/
error ZeroLengthArray();
/**
* Thrown when an undefined archetype is provided.
*/
error UndefinedArchetype();
/**
* Thrown when an empty ability name is provided.
*/
error EmptyName();
/**
* Thrown when an undefined AbilityStars value is provided.
*/
error UndefinedAbilityStars();
/**
* Thrown when the zero address is provided as input.
*/
error ZeroAddress();
/**
* Thrown when the sum of weights doesn't equal 10_000.
*/
error InvalidWeightSum();
/**
* Thrown when a non-existent ability ID is provided.
*/
error NonExistentAbilityId();
/**
* Thrown when `Game.CardTier.UNDEFINED` is provided when updating weights.
*/
error UndefinedCardTier();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ENUMS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Enum encapsulating the number of stars that can be associated with an ability.
*/
enum AbilityStars {
UNDEFINED,
ONE,
TWO,
THREE
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Struct encapsulating an Ability.
* @param name Name of the ability.
* @param stars Star tier.
* @param archetype Related archetype.
*/
struct Ability {
string name;
AbilityStars stars;
uint16 archetype;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when an ability is added.
* @param abilityId Unique ability identifier.
* @param newAbility The new ability that was added.
*/
event AbilityAdded(uint256 indexed abilityId, Ability newAbility);
/**
* Emitted when an ability is removed.
* @param abilityId Unique ability idenitfier.
* @param ability Ability that has been removed.
*/
event AbilityRemoved(uint256 indexed abilityId, Ability ability);
/**
* Emitted when the name of an ability is updated.
* @param abilityId Unique ability identifier.
* @param oldName Old ability name.
* @param newName New ability name.
*/
event AbilityNameUpdated(uint256 indexed abilityId, string oldName, string newName);
/**
* Emitted when card tier ability weights are updated.
* @param cardTier Game.CardTier value.
* @param oldWeights Old weight values.
* @param newWeights New weight values.
*/
event WeightsUpdated(Game.CardTier cardTier, uint256[3] oldWeights, uint256[3] newWeights);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to view the total number of abilities.
*/
function abilityCount() external view returns (uint256);
/**
* Function used to add abilities.
* @param newAbilities Array of abilities to add.
*/
function addAbilities(Ability[] calldata newAbilities) external;
/**
* Function used to edit an already existing ability name.
* @param abilityId Unique ability identifier.
* @param newName Newly desired name value.
*/
function editAbilityName(uint256 abilityId, string calldata newName) external;
/**
* Function used to remove an ability.
* @param abilityId Unique ability idenitifer.
* @custom:note This function should be called with extreme caution as removing an ability already associated with a
* tokenized card break the game.
*/
function removeAbility(uint256 abilityId) external;
/**
* Function used to get abilities for a card.
* @param cardTier Tier of the card.
* @param archetypes Archetypes associated with the card.
* @param ephemeralSeed Seed used to "randomise" ability choices.
*/
function getCardAbilities(
Game.CardTier cardTier,
uint16[] calldata archetypes,
uint256 ephemeralSeed
) external view returns (uint256[3] memory abilities);
/**
* Function used to update card tier ability weights.
* @param cardTier Card tier to update weights for.
* @param updatedWeights Updated card tier weights.
*/
function updateWeights(Game.CardTier cardTier, uint256[3] calldata updatedWeights) external;
/**
* Function used to view the ability associated with an ID.
* @param abilityId Unique ability identifier.
*/
function idToAbility(uint256 abilityId) external view returns (Ability memory);
/**
* Function used to view the sorted abilities for a given archetype at a specified star tier.
* @param archetype Archetype of the unit.
* @param stars Star tier rating to lookup.
*/
function sortedAbilities(uint16 archetype, AbilityStars stars) external view returns (uint256[] memory);
/**
* Function used to view the star tier weights of a given card tier.
* @param cardTier Tier of card to check weights for.
*/
function weights(Game.CardTier cardTier) external view returns (uint256[3] memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import { Game } from "../types/Game.sol";
/**
* @title MetadataRenderer
* @notice Interface for MetadataRenderer.
*/
interface IMetadataRenderer {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided.
*/
error ZeroAddressInvalid();
/**
* Thrown when a unit name is unable to be parsed.
*/
error UndefinedUnitName();
/**
* Thrown when a card tier is unable to be parsed.
*/
error UndefinedCardTier();
/**
* Thrown when a card archetype is unable to be parsed.
*/
error UndefinedArchetype();
/**
* Thrown when an ability stars value is unable to be parsed.
*/
error UndefinedAbilityStars();
/**
* Thrown when a card type is unable to be parsed.
*/
error UndefinedCardType();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when the `Abilities` contract address is updated.
* @param oldAbilities Old `Abilities` contract address.
* @param newAbilities New `Abilities` contract address.
*/
event AbilitiesUpdated(address oldAbilities, address newAbilities);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function that returns the JSON metadata of a specified tokenized card.
* @param tokenId Unique Cards token identifier.
* @param playerCard Tokenised player card.
* @param baseCard Underlying base card from which the tokenised card was derived from.
*/
function getMetadata(
uint256 tokenId,
Game.PlayerCard calldata playerCard,
Game.BaseCard calldata baseCard
) external view returns (string memory);
/**
* Function used to set a new `abilities` address.
* @param newAbilities New `abilities` address.
*/
function setAbilities(address newAbilities) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/**
* @title IBlast
* @notice Interface for Blast.
*/
interface IBlast {
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint256);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/**
* @title Game
* @notice This library contains shared data types and structures that are used within the game.
*/
/**
* Namespace used to encapsulate shared game data types and structures.
*/
library Game {
/**
* Enum encapsulating the various tiers that can be associated with a card.
*/
enum CardTier {
UNDEFINED,
C,
B,
A,
S,
SS,
SSS
}
/**
* Enum encapsulating the possible card types.
*/
enum CardType {
UNDEFINED,
UNIT,
ARTIFACT
}
/**
* Struct encapsulating general card stats.
* @param HP Health Points.
* @param PWR Base Power.
* @param DEF Base Defense.
* @param SPD Base Attack Speed.
*/
struct Stats {
uint256 HP;
uint256 PWR;
uint256 DEF;
uint256 SPD;
}
/**
* Struct encapsulating information related to a unit base card.
* @param name Name of the unit.
* @param imageURI Unique resource identifier for the unit image.
* @param unitType Type of unit the base card is.
* @param stats Base stats of the unit.
* @param archetypes Archetypes related to the unit.
*/
struct Unit {
string name;
string imageURI;
uint16 unitType;
Stats stats;
uint16[] archetypes;
}
/**
* Struct encapsulating information related to an artifact base card.
* @param name Name of the artifact.
* @param imageURI Unique resource idenitifier for the artifact image.
* @param cardTier Base card tier of the artifact.
* @param archetypes Archetypes related to the artifact.
*/
struct Artifact {
string name;
string imageURI;
CardTier cardTier;
uint16[] archetypes;
}
/**
* Struct encapsulating information related to a base card.
* @param name Name of the base card, this will either be the name of the unit or the artifact.
* @param imageURI Unique resource identifier for the image, this will either be an image of a unit or an artifact.
* @param cardType Either an artifact or a unit.
* @param cardTier For artifacts this will be constant. For units, a tier will be determined upon mint.
* @param stats For artifacts all stats will be 0. For units, stats will be determined upon mint.
* @param archetypes Archetypes related to the underlying base card.
*/
struct BaseCard {
string name;
string imageURI;
CardType cardType;
CardTier cardTier;
uint16 unitType;
Stats stats;
uint16[] archetypes;
}
/**
* Struct encapsulating information related to a tokenized player card.
* @param baseCardId Base card identifier associated with the player card.
* @param serialNumber The number which indicates how many of this card existed at mint.
* @param level Level of the card.
* @param cardType Indicates if this card is an artifact or unit.
* @param cardTier For artifacts this will be constant. For units, a tier will be determined upon mint.
* @param unitType Type of unit associated with this card, an artifact will yield a `0` value.
* @param stats For artifacts all stats will be 0. For units, stats will be determined upon mint.
* @param archetypes Archetypes associated with the player card.
* @param abilityIds Abilities associated with the player card.
*/
struct PlayerCard {
uint256 baseCardId;
uint256 serialNumber;
uint256 level;
CardType cardType;
CardTier cardTier;
uint16 unitType;
Stats stats;
uint16[] archetypes;
uint256[3] abilityIds;
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../IERC721AUpgradeable.sol';
/**
* @dev Interface of ERC721ABurnable.
*/
interface IERC721ABurnableUpgradeable is IERC721AUpgradeable {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721AUpgradeable.sol';
import {ERC721AStorage} from './ERC721AStorage.sol';
import './ERC721A__Initializable.sol';
/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721A__IERC721ReceiverUpgradeable {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC721A
*
* @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
* Non-Fungible Token Standard, including the Metadata extension.
* Optimized for lower gas during batch mints.
*
* Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
* starting from `_startTokenId()`.
*
* Assumptions:
*
* - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
* - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721AUpgradeable is ERC721A__Initializable, IERC721AUpgradeable {
using ERC721AStorage for ERC721AStorage.Layout;
// =============================================================
// CONSTANTS
// =============================================================
// Mask of an entry in packed address data.
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
// The bit position of `numberMinted` in packed address data.
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
// The bit position of `numberBurned` in packed address data.
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
// The bit position of `aux` in packed address data.
uint256 private constant _BITPOS_AUX = 192;
// Mask of all 256 bits in packed address data except the 64 bits for `aux`.
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
// The bit position of `startTimestamp` in packed ownership.
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
// The bit mask of the `burned` bit in packed ownership.
uint256 private constant _BITMASK_BURNED = 1 << 224;
// The bit position of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
// The bit mask of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
// The bit position of `extraData` in packed ownership.
uint256 private constant _BITPOS_EXTRA_DATA = 232;
// Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The maximum `quantity` that can be minted with {_mintERC2309}.
// This limit is to prevent overflows on the address data entries.
// For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
// is required to cause an overflow, which is unrealistic.
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// =============================================================
// CONSTRUCTOR
// =============================================================
function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
__ERC721A_init_unchained(name_, symbol_);
}
function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
ERC721AStorage.layout()._name = name_;
ERC721AStorage.layout()._symbol = symbol_;
ERC721AStorage.layout()._currentIndex = _startTokenId();
}
// =============================================================
// TOKEN COUNTING OPERATIONS
// =============================================================
/**
* @dev Returns the starting token ID.
* To change the starting token ID, please override this function.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view virtual returns (uint256) {
return ERC721AStorage.layout()._currentIndex;
}
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() public view virtual override returns (uint256) {
// Counter underflow is impossible as _burnCounter cannot be incremented
// more than `_currentIndex - _startTokenId()` times.
unchecked {
return ERC721AStorage.layout()._currentIndex - ERC721AStorage.layout()._burnCounter - _startTokenId();
}
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view virtual returns (uint256) {
// Counter underflow is impossible as `_currentIndex` does not decrement,
// and it is initialized to `_startTokenId()`.
unchecked {
return ERC721AStorage.layout()._currentIndex - _startTokenId();
}
}
/**
* @dev Returns the total number of tokens burned.
*/
function _totalBurned() internal view virtual returns (uint256) {
return ERC721AStorage.layout()._burnCounter;
}
// =============================================================
// ADDRESS DATA OPERATIONS
// =============================================================
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return ERC721AStorage.layout()._packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
return
(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
return
(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
return uint64(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_AUX);
}
/**
* Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = ERC721AStorage.layout()._packedAddressData[owner];
uint256 auxCasted;
// Cast `aux` with assembly to avoid redundant masking.
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
ERC721AStorage.layout()._packedAddressData[owner] = packed;
}
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return
interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return ERC721AStorage.layout()._name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return ERC721AStorage.layout()._symbol;
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, it can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return '';
}
// =============================================================
// OWNERSHIPS OPERATIONS
// =============================================================
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
/**
* @dev Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around over time.
*/
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
/**
* @dev Returns the unpacked `TokenOwnership` struct at `index`.
*/
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]);
}
/**
* @dev Initializes the ownership slot minted at `index` for efficiency purposes.
*/
function _initializeOwnershipAt(uint256 index) internal virtual {
if (ERC721AStorage.layout()._packedOwnerships[index] == 0) {
ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index);
}
}
/**
* Returns the packed ownership data of `tokenId`.
*/
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
if (_startTokenId() <= tokenId) {
packed = ERC721AStorage.layout()._packedOwnerships[tokenId];
// If not burned.
if (packed & _BITMASK_BURNED == 0) {
// If the data at the starting slot does not exist, start the scan.
if (packed == 0) {
if (tokenId >= ERC721AStorage.layout()._currentIndex) revert OwnerQueryForNonexistentToken();
// Invariant:
// There will always be an initialized ownership slot
// (i.e. `ownership.addr != address(0) && ownership.burned == false`)
// before an unintialized ownership slot
// (i.e. `ownership.addr == address(0) && ownership.burned == false`)
// Hence, `tokenId` will not underflow.
//
// We can directly compare the packed value.
// If the address is zero, packed will be zero.
for (;;) {
unchecked {
packed = ERC721AStorage.layout()._packedOwnerships[--tokenId];
}
if (packed == 0) continue;
return packed;
}
}
// Otherwise, the data exists and is not burned. We can skip the scan.
// This is possible because we have already achieved the target condition.
// This saves 2143 gas on transfers of initialized tokens.
return packed;
}
}
revert OwnerQueryForNonexistentToken();
}
/**
* @dev Returns the unpacked `TokenOwnership` struct from `packed`.
*/
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
/**
* @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
*/
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
// For branchless setting of the `nextInitialized` flag.
assembly {
// `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
*/
function approve(address to, uint256 tokenId) public payable virtual override {
_approve(to, tokenId, true);
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return ERC721AStorage.layout()._tokenApprovals[tokenId].value;
}
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return ERC721AStorage.layout()._operatorApprovals[owner][operator];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted. See {_mint}.
*/
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return
_startTokenId() <= tokenId &&
tokenId < ERC721AStorage.layout()._currentIndex && // If within bounds,
ERC721AStorage.layout()._packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
}
/**
* @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
*/
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
msgSender := and(msgSender, _BITMASK_ADDRESS)
// `msgSender == owner || msgSender == approvedAddress`.
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId`.
*/
function _getApprovedSlotAndAddress(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, address approvedAddress)
{
ERC721AStorage.TokenApprovalRef storage tokenApproval = ERC721AStorage.layout()._tokenApprovals[tokenId];
// The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
// =============================================================
// TRANSFER OPERATIONS
// =============================================================
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
if (to == address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// We can directly increment and decrement the balances.
--ERC721AStorage.layout()._packedAddressData[from]; // Updates: `balance -= 1`.
++ERC721AStorage.layout()._packedAddressData[to]; // Updates: `balance += 1`.
// Updates:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
/**
* @dev Hook that is called before a set of serially-ordered token IDs
* are about to be transferred. This includes minting.
* And also called before burning one token.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token IDs
* have been transferred. This includes minting.
* And also called after one token has been burned.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* `from` - Previous owner of the given token ID.
* `to` - Target address that will receive the token.
* `tokenId` - Token ID to be transferred.
* `_data` - Optional data to send along with the call.
*
* Returns whether the call correctly returned the expected magic value.
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try
ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data)
returns (bytes4 retval) {
return retval == ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
// =============================================================
// MINT OPERATIONS
// =============================================================
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event for each mint.
*/
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
if (quantity == 0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// `balance` and `numberMinted` have a maximum limit of 2**64.
// `tokenId` has a maximum limit of 2**256.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
uint256 toMasked;
uint256 end = startTokenId + quantity;
// Use assembly to loop and emit the `Transfer` event for gas savings.
// The duplicated `log4` removes an extra check and reduces stack juggling.
// The assembly, together with the surrounding Solidity code, have been
// delicately arranged to nudge the compiler into producing optimized opcodes.
assembly {
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
toMasked := and(to, _BITMASK_ADDRESS)
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
startTokenId // `tokenId`.
)
// The `iszero(eq(,))` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
// The compiler will optimize the `iszero` away for performance.
for {
let tokenId := add(startTokenId, 1)
} iszero(eq(tokenId, end)) {
tokenId := add(tokenId, 1)
} {
// Emit the `Transfer` event. Similar to above.
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
}
}
if (toMasked == 0) revert MintToZeroAddress();
ERC721AStorage.layout()._currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* This function is intended for efficient minting only during contract creation.
*
* It emits only one {ConsecutiveTransfer} as defined in
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
* instead of a sequence of {Transfer} event(s).
*
* Calling this function outside of contract creation WILL make your contract
* non-compliant with the ERC721 standard.
* For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
* {ConsecutiveTransfer} event is only permissible during contract creation.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {ConsecutiveTransfer} event.
*/
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are unrealistic due to the above check for `quantity` to be below the limit.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
ERC721AStorage.layout()._currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* See {_mint}.
*
* Emits a {Transfer} event for each mint.
*/
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = ERC721AStorage.layout()._currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
} while (index < end);
// Reentrancy protection.
if (ERC721AStorage.layout()._currentIndex != end) revert();
}
}
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_approve(to, tokenId, false)`.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_approve(to, tokenId, false);
}
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function _approve(
address to,
uint256 tokenId,
bool approvalCheck
) internal virtual {
address owner = ownerOf(tokenId);
if (approvalCheck)
if (_msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
revert ApprovalCallerNotOwnerNorApproved();
}
ERC721AStorage.layout()._tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
// =============================================================
// BURN OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// Updates:
// - `balance -= 1`.
// - `numberBurned += 1`.
//
// We can directly decrement the balance, and increment the number burned.
// This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
ERC721AStorage.layout()._packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
// Updates:
// - `address` to the last owner.
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
unchecked {
ERC721AStorage.layout()._burnCounter++;
}
}
// =============================================================
// EXTRA DATA OPERATIONS
// =============================================================
/**
* @dev Directly sets the extra data for the ownership data `index`.
*/
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = ERC721AStorage.layout()._packedOwnerships[index];
if (packed == 0) revert OwnershipNotInitializedForExtraData();
uint256 extraDataCasted;
// Cast `extraData` with assembly to avoid redundant masking.
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
ERC721AStorage.layout()._packedOwnerships[index] = packed;
}
/**
* @dev Called during each token transfer to set the 24bit `extraData` field.
* Intended to be overridden by the cosumer contract.
*
* `previousExtraData` - the value of `extraData` before transfer.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _extraData(
address from,
address to,
uint24 previousExtraData
) internal view virtual returns (uint24) {}
/**
* @dev Returns the next extra data for the packed ownership data.
* The returned result is shifted into position.
*/
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
// =============================================================
// OTHER OPERATIONS
// =============================================================
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
/**
* @dev Converts a uint256 to its ASCII string decimal representation.
*/
function _toString(uint256 value) internal pure virtual returns (string memory str) {
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
let m := add(mload(0x40), 0xa0)
// Update the free memory pointer to allocate.
mstore(0x40, m)
// Assign the `str` to the end.
str := sub(m, 0x20)
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// prettier-ignore
for { let temp := value } 1 {} {
str := sub(str, 1)
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
// prettier-ignore
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable diamond facet contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
import {ERC721A__InitializableStorage} from './ERC721A__InitializableStorage.sol';
abstract contract ERC721A__Initializable {
using ERC721A__InitializableStorage for ERC721A__InitializableStorage.Layout;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializerERC721A() {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(
ERC721A__InitializableStorage.layout()._initializing
? _isConstructor()
: !ERC721A__InitializableStorage.layout()._initialized,
'ERC721A__Initializable: contract is already initialized'
);
bool isTopLevelCall = !ERC721A__InitializableStorage.layout()._initializing;
if (isTopLevelCall) {
ERC721A__InitializableStorage.layout()._initializing = true;
ERC721A__InitializableStorage.layout()._initialized = true;
}
_;
if (isTopLevelCall) {
ERC721A__InitializableStorage.layout()._initializing = false;
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializingERC721A() {
require(
ERC721A__InitializableStorage.layout()._initializing,
'ERC721A__Initializable: contract is not initializing'
);
_;
}
/// @dev Returns true if and only if the function is running in the constructor
function _isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
address self = address(this);
uint256 cs;
assembly {
cs := extcodesize(self)
}
return cs == 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/// @dev Cannot double-initialize.
error AlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
revert(0x1c, 0x04)
}
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(_OWNER_SLOT, newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721AUpgradeable.sol';
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721AUpgradeable {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external payable;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library ERC721AStorage {
// Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
struct TokenApprovalRef {
address value;
}
struct Layout {
// =============================================================
// STORAGE
// =============================================================
// The next token ID to be minted.
uint256 _currentIndex;
// The number of tokens burned.
uint256 _burnCounter;
// Token name
string _name;
// Token symbol
string _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned.
// See {_packedOwnershipOf} implementation for details.
//
// Bits Layout:
// - [0..159] `addr`
// - [160..223] `startTimestamp`
// - [224] `burned`
// - [225] `nextInitialized`
// - [232..255] `extraData`
mapping(uint256 => uint256) _packedOwnerships;
// Mapping owner address to address data.
//
// Bits Layout:
// - [0..63] `balance`
// - [64..127] `numberMinted`
// - [128..191] `numberBurned`
// - [192..255] `aux`
mapping(address => uint256) _packedAddressData;
// Mapping from token ID to approved address.
mapping(uint256 => ERC721AStorage.TokenApprovalRef) _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) _operatorApprovals;
}
bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.ERC721A');
function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is a base storage for the initialization function for upgradeable diamond facet contracts
**/
library ERC721A__InitializableStorage {
struct Layout {
/*
* Indicates that the contract has been initialized.
*/
bool _initialized;
/*
* Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.initializable.facet');
function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@erc721a-upgradeable/=lib/ERC721A-Upgradeable/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"@openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"@openzeppelin-contracts/=lib/openzeppelin-contracts/",
"@solady/=lib/solady/",
"@v2-core/=lib/v2-core/contracts/",
"@v2-periphery/=lib/v2-periphery/contracts/",
"ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solady/=lib/solady/",
"v2-core/=lib/v2-core/contracts/",
"v2-periphery/=lib/v2-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CallerNotOwner","type":"error"},{"inputs":[],"name":"CardLevelMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidCardLevel","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidMaxLevel","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NonExistentTokenId","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"SignerMismatch","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroLengthArray","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAbilities","type":"address"},{"indexed":false,"internalType":"address","name":"newAbilities","type":"address"}],"name":"AbilitiesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBaseCards","type":"address"},{"indexed":false,"internalType":"address","name":"newBaseCards","type":"address"}],"name":"BaseCardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldLevel","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLevel","type":"uint256"}],"name":"LevelUp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxLevel","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxLevel","type":"uint256"}],"name":"MaxCardLevelUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldMetadataRenderer","type":"address"},{"indexed":false,"internalType":"address","name":"newMetadataRenderer","type":"address"}],"name":"MetadataRendererUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint256","name":"baseCardId","type":"uint256"},{"internalType":"uint256","name":"serialNumber","type":"uint256"},{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"enum Game.CardType","name":"cardType","type":"uint8"},{"internalType":"enum Game.CardTier","name":"cardTier","type":"uint8"},{"internalType":"uint16","name":"unitType","type":"uint16"},{"components":[{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"PWR","type":"uint256"},{"internalType":"uint256","name":"DEF","type":"uint256"},{"internalType":"uint256","name":"SPD","type":"uint256"}],"internalType":"struct Game.Stats","name":"stats","type":"tuple"},{"internalType":"uint16[]","name":"archetypes","type":"uint16[]"},{"internalType":"uint256[3]","name":"abilityIds","type":"uint256[3]"}],"indexed":false,"internalType":"struct Game.PlayerCard","name":"newPlayerCard","type":"tuple"}],"name":"PlayerCardDefined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSeeder","type":"address"},{"indexed":false,"internalType":"address","name":"newSeeder","type":"address"}],"name":"SeederUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":true,"internalType":"address","name":"newSigner","type":"address"}],"name":"SignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"level","type":"uint256"},{"components":[{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"PWR","type":"uint256"},{"internalType":"uint256","name":"DEF","type":"uint256"},{"internalType":"uint256","name":"SPD","type":"uint256"}],"indexed":false,"internalType":"struct Game.Stats","name":"oldStatModifiers","type":"tuple"},{"components":[{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"PWR","type":"uint256"},{"internalType":"uint256","name":"DEF","type":"uint256"},{"internalType":"uint256","name":"SPD","type":"uint256"}],"indexed":false,"internalType":"struct Game.Stats","name":"newStatModifiers","type":"tuple"}],"name":"StatModifiersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"BLAST","outputs":[{"internalType":"contract IBlast","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"abilities","outputs":[{"internalType":"contract ICardAbilities","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseCards","outputs":[{"internalType":"contract IBaseCards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"incinerate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_gameMaster","type":"address"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_seeder","type":"address"},{"internalType":"address","name":"_baseCards","type":"address"},{"internalType":"address","name":"_abilities","type":"address"},{"internalType":"address","name":"_metadataRenderer","type":"address"},{"internalType":"address","name":"_blastGovernor","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"newLevel","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"levelUpCard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxCardLevel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataRenderer","outputs":[{"internalType":"contract IMetadataRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"},{"internalType":"uint256[6]","name":"tierWeights","type":"uint256[6]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mintCards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"playerCards","outputs":[{"components":[{"internalType":"uint256","name":"baseCardId","type":"uint256"},{"internalType":"uint256","name":"serialNumber","type":"uint256"},{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"enum Game.CardType","name":"cardType","type":"uint8"},{"internalType":"enum Game.CardTier","name":"cardTier","type":"uint8"},{"internalType":"uint16","name":"unitType","type":"uint16"},{"components":[{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"PWR","type":"uint256"},{"internalType":"uint256","name":"DEF","type":"uint256"},{"internalType":"uint256","name":"SPD","type":"uint256"}],"internalType":"struct Game.Stats","name":"stats","type":"tuple"},{"internalType":"uint16[]","name":"archetypes","type":"uint16[]"},{"internalType":"uint256[3]","name":"abilityIds","type":"uint256[3]"}],"internalType":"struct Game.PlayerCard","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"seeder","outputs":[{"internalType":"contract ISeeder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseCardId","type":"uint256"}],"name":"serialNumbers","outputs":[{"internalType":"uint256","name":"serialNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAbilities","type":"address"}],"name":"setAbilities","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newBaseCards","type":"address"}],"name":"setBaseCards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"level","type":"uint256"},{"components":[{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"PWR","type":"uint256"},{"internalType":"uint256","name":"DEF","type":"uint256"},{"internalType":"uint256","name":"SPD","type":"uint256"}],"internalType":"struct Game.Stats","name":"modifiers","type":"tuple"}],"name":"setCardLevelModifiers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxLevel","type":"uint256"}],"name":"setMaxCardLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMetadataRenderer","type":"address"}],"name":"setMetadataRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSeeder","type":"address"}],"name":"setSeeder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSigner","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cardLevel","type":"uint256"}],"name":"statModifiers","outputs":[{"components":[{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"PWR","type":"uint256"},{"internalType":"uint256","name":"DEF","type":"uint256"},{"internalType":"uint256","name":"SPD","type":"uint256"}],"internalType":"struct Game.Stats","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60c06040523060805273430000000000000000000000000000000000000260a0523480156200002d57600080fd5b50620000386200003e565b620000f2565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156200008f5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000ef5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b60805160a0516157ee62000134600039600081816108c4015281816120820152612143015260008181613a0501528181613a2e0152613c4d01526157ee6000f3fe60806040526004361061033f5760003560e01c806354d1f13d116101b057806397d75776116100ec578063d50b31eb11610095578063f04e283e1161006f578063f04e283e14610a64578063f2fde38b14610a77578063fd4fe8a814610a8a578063fee81cf414610aaa57600080fd5b8063d50b31eb146109a2578063e0a04d71146109c2578063e985e9c5146109ef57600080fd5b8063b88d4fde116100c6578063b88d4fde1461094f578063c87b56dd14610962578063cf46fd011461098257600080fd5b806397d75776146108b2578063a22cb465146108e6578063ad3cb1cc1461090657600080fd5b8063715018a61161015957806381fbd3291161013357806381fbd3291461081c5780638a29e2de146108495780638da5cb5b1461086957806395d89b411461089d57600080fd5b8063715018a6146107c75780637a7932f5146107cf5780637afb9b1d146107ef57600080fd5b80636c19e7831161018a5780636c19e7831461075a578063703199701461077a57806370a08231146107a757600080fd5b806354d1f13d146107055780636352211e1461070d578063684931ed1461072d57600080fd5b8063256929621161027f57806342842e0e116102285780634dc0884f116102025780634dc0884f146106795780634f1ef286146106a6578063514e62fc146106b957806352d1902d146106f057600080fd5b806342842e0e1461063357806342966c68146106465780634a4ee7b11461066657600080fd5b806332e12cb91161025957806332e12cb9146105c657806335022122146105e65780633ec565081461061357600080fd5b8063256929621461056b578063295bbecd146105735780632de948071461059357600080fd5b806318160ddd116102ec5780631cd64df4116102c65780631cd64df4146104de578063238ac9331461051557806323b872dd1461054257806323f849701461055557600080fd5b806318160ddd14610435578063183a4f6e146104b85780631c10893f146104cb57600080fd5b8063081812fc1161031d578063081812fc146103bd578063095ea7b31461040257806311e2dc9b1461041557600080fd5b806301ffc9a71461034457806303728ca31461037957806306fdde031461039b575b600080fd5b34801561035057600080fd5b5061036461035f366004614867565b610add565b60405190151581526020015b60405180910390f35b34801561038557600080fd5b506103996103943660046148f4565b610bc2565b005b3480156103a757600080fd5b506103b0610c71565b60405161037091906149ce565b3480156103c957600080fd5b506103dd6103d83660046149e1565b610d25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610370565b6103996104103660046149fa565b610dae565b34801561042157600080fd5b50610399610430366004614a24565b610dbe565b34801561044157600080fd5b507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c41547f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4054037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b604051908152602001610370565b6103996104c63660046149e1565b610ef4565b6103996104d93660046149fa565b610f01565b3480156104ea57600080fd5b506103646104f93660046149fa565b638b78c6d8600c90815260009290925260209091205481161490565b34801561052157600080fd5b506007546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b610399610550366004614a7a565b610f13565b34801561056157600080fd5b506104aa60085481565b6103996112b0565b34801561057f57600080fd5b5061039961058e366004614ab6565b611300565b34801561059f57600080fd5b506104aa6105ae366004614b36565b638b78c6d8600c908152600091909152602090205490565b3480156105d257600080fd5b506103996105e1366004614b36565b6115a0565b3480156105f257600080fd5b506106066106013660046149e1565b611680565b6040516103709190614b51565b34801561061f57600080fd5b5061039961062e366004614b36565b611734565b610399610641366004614a7a565b61180b565b34801561065257600080fd5b506103996106613660046149e1565b61182b565b6103996106743660046149fa565b611836565b34801561068557600080fd5b506106996106943660046149e1565b611848565b6040516103709190614cf5565b6103996106b4366004614e4b565b611a46565b3480156106c557600080fd5b506103646106d43660046149fa565b638b78c6d8600c90815260009290925260209091205416151590565b3480156106fc57600080fd5b506104aa611a61565b610399611a90565b34801561071957600080fd5b506103dd6107283660046149e1565b611acc565b34801561073957600080fd5b506003546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561076657600080fd5b50610399610775366004614b36565b611ad7565b34801561078657600080fd5b506006546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107b357600080fd5b506104aa6107c2366004614b36565b611ba7565b610399611c48565b3480156107db57600080fd5b506103996107ea3660046149e1565b611c5c565b3480156107fb57600080fd5b506004546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561082857600080fd5b506104aa6108373660046149e1565b60026020526000908152604090205481565b34801561085557600080fd5b50610399610864366004614e99565b611cdf565b34801561087557600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546103dd565b3480156108a957600080fd5b506103b0612368565b3480156108be57600080fd5b506103dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108f257600080fd5b50610399610901366004614f30565b612399565b34801561091257600080fd5b506103b06040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b61039961095d366004614f6c565b61244f565b34801561096e57600080fd5b506103b061097d3660046149e1565b6124bf565b34801561098e57600080fd5b5061039961099d366004614fc8565b61282f565b3480156109ae57600080fd5b506103996109bd366004614b36565b6128b5565b3480156109ce57600080fd5b506005546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109fb57600080fd5b50610364610a0a36600461500a565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832093909416825291909152205460ff1690565b610399610a72366004614b36565b61298c565b610399610a85366004614b36565b6129c9565b348015610a9657600080fd5b50610399610aa5366004614b36565b6129f0565b348015610ab657600080fd5b506104aa610ac5366004614b36565b63389a75e1600c908152600091909152602090205490565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610b7057507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610bbc57507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6004610bcd81612ac7565b6000849003610c08576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610c55576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c60858585612aed565b610c6a8285613042565b5050505050565b60607f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c406002018054610ca29061503d565b80601f0160208091040260200160405190810160405280929190818152602001828054610cce9061503d565b8015610d1b5780601f10610cf057610100808354040283529160200191610d1b565b820191906000526020600020905b815481529060010190602001808311610cfe57829003601f168201915b5050505050905090565b6000610d30826131fc565b610d66576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c46602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b610dba82826001613288565b5050565b6001610dc981612ac7565b600183111580610dda575060085483115b15610e11576040517f7601ab6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260016020818152604080842081516080810183528154815281850180548286015260028301805483860152600384018054606080860191909152988c905296865289358455948901359055918701359092559285013590915550837f74d75c7983755f1c284547da8f27cd36cb59934a29590b598cea9b9810f04cc08285604051610ee692919082518152602080840151818301526040808501518184015260609485015185840152833560808401529083013560a083015282013560c082015291013560e08201526101000190565b60405180910390a250505050565b610efe33826133e2565b50565b610f096133ee565b610dba8282613424565b6000610f1e82613430565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610f85576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c46602052604090208054610fdd8187335b73ffffffffffffffffffffffffffffffffffffffff9081169116811491141790565b61106a5773ffffffffffffffffffffffffffffffffffffffff861660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832033845290915290205460ff1661106a576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85166110b7576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156110c257600082555b73ffffffffffffffffffffffffffffffffffffffff86811660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c45602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055918716808252919020805460010190554260a01b177c02000000000000000000000000000000000000000000000000000000001760008581527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260408120919091557c02000000000000000000000000000000000000000000000000000000008416900361124c576001840160008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c446020526040812054900361124a577f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4054811461124a5760008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c44602052604090208490555b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b505050505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b611309846131fc565b61133f576040517f96f1504a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61134884611acc565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146113ac576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008548311156113e8576040517f7601ab6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260208190526040812060020180548290611406906150bf565b91829055509050838114611446576040517f7c139f5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006114a88686604051602001611467929190918252602082015260400190565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b600754604080516020601f880181900481028201810190925286815292935073ffffffffffffffffffffffffffffffffffffffff9091169161150791879087908190840183828082843760009201919091525086939250506135819050565b73ffffffffffffffffffffffffffffffffffffffff1614611554576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b857f66833f6d7d7a01eaed9fb21eb9cc54f0fb9497fa9251a6c0773372c8d3e0aa0c6115816001856150f7565b60408051918252602082018690520160405180910390a2505050505050565b60016115ab81612ac7565b73ffffffffffffffffffffffffffffffffffffffff82166115f8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527fba77f4757246a5ae4182e908698755b395d9654a76ebe7623c8eba114dd7ebdf91015b60405180910390a1505050565b6116ab6040518060800160405280600081526020016000815260200160008152602001600081525090565b8115806116b9575060085482115b156116f0576040517f6e1e14c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000908152600160208181526040928390208351608081018552815481529281015491830191909152600281015492820192909252600390910154606082015290565b600161173f81612ac7565b73ffffffffffffffffffffffffffffffffffffffff821661178c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f35caef78b01a683ca840d6cd59416128819f56369fa6dc9049298a812a35e7039101611673565b6118268383836040518060200160405280600081525061244f565b505050565b610efe81600161362b565b61183e6133ee565b610dba82826133e2565b6118506146a0565b611859826131fc565b61188f576040517f96f1504a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260208181526040808320815161012081018352815481526001820154938101939093526002808201549284019290925260038101549091606084019160ff16908111156118e3576118e3614b7c565b60028111156118f4576118f4614b7c565b81526020016003820160019054906101000a900460ff16600681111561191c5761191c614b7c565b600681111561192d5761192d614b7c565b8152600382015462010000900461ffff166020808301919091526040805160808101825260048501548152600585015481840152600685015481830152600785015460608083019190915282850191909152600885018054835181860281018601909452808452919094019391928301828280156119f257602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116119b95790505b505050918352505060408051606081019182905260209092019190600984019060039082845b815481526020019060010190808311611a18575050505050815250509050611a3f816138fd565b9392505050565b611a4e6139ed565b611a5782613af1565b610dba8282613afc565b6000611a6b613c35565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6000610bbc82613430565b6001611ae281612ac7565b73ffffffffffffffffffffffffffffffffffffffff8216611b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb90600090a3505050565b600073ffffffffffffffffffffffffffffffffffffffff8216611bf6576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff1660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c45602052604090205467ffffffffffffffff1690565b611c506133ee565b611c5a6000613ca4565b565b6001611c6781612ac7565b81600003611ca1576040517f6e1e14c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600880549083905560408051828152602081018590527f92d27f4a98ff8c3157777f442f548d5615527466d86e12b028b7744e6ffbc2799101611673565b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff16611d38577fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f5460ff1615611d3c565b303b155b611dcd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e747261637460448201527f20697320616c726561647920696e697469616c697a656400000000000000000060648201526084015b60405180910390fd5b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff16158015611e4a577fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015611e955750825b905060008267ffffffffffffffff166001148015611eb25750303b155b905081158015611ec0575080155b15611ef7576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315611f585784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff8e161580611f8f575073ffffffffffffffffffffffffffffffffffffffff8d16155b80611fae575073ffffffffffffffffffffffffffffffffffffffff8c16155b80611fcd575073ffffffffffffffffffffffffffffffffffffffff8b16155b80611fec575073ffffffffffffffffffffffffffffffffffffffff8a16155b8061200b575073ffffffffffffffffffffffffffffffffffffffff8916155b8061202a575073ffffffffffffffffffffffffffffffffffffffff8816155b80612049575073ffffffffffffffffffffffffffffffffffffffff8716155b15612080576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156120e857600080fd5b505af11580156120fc573d6000803e3d6000fd5b50506040517feb86469800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301527f000000000000000000000000000000000000000000000000000000000000000016925063eb8646989150602401600060405180830381600087803b15801561218957600080fd5b505af115801561219d573d6000803e3d6000fd5b505050506122156040518060400160405280600a81526020017f47616d65204361726473000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f4341524453000000000000000000000000000000000000000000000000000000815250613d0a565b61221e8e613dca565b6122298d6001613424565b600780547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8f811691909117909255600a6008556003805482168e84161790556004805482168d84161790556005805482168c841617905560068054909116918a16919091179055831561230a5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050801561235d577fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b505050505050505050565b60607f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c406003018054610ca29061503d565b3360008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b61245a848484610f13565b73ffffffffffffffffffffffffffffffffffffffff83163b156124b95761248384848484613e2e565b6124b9576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60606124ca826131fc565b612500576040517f96f1504a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260208181526040808320815161012081018352815481526001820154938101939093526002808201549284019290925260038101549091606084019160ff169081111561255457612554614b7c565b600281111561256557612565614b7c565b81526020016003820160019054906101000a900460ff16600681111561258d5761258d614b7c565b600681111561259e5761259e614b7c565b8152600382015462010000900461ffff1660208083019190915260408051608081018252600485015481526005850154818401526006850154818301526007850154606080830191909152828501919091526008850180548351818602810186019094528084529190940193919283018282801561266357602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161262a5790505b505050918352505060408051606081019182905260209092019190600984019060039082845b8154815260200190600101908083116126895750505050508152505090506126b0816138fd565b6004805482516040517fabb051740000000000000000000000000000000000000000000000000000000081529283015291925060009173ffffffffffffffffffffffffffffffffffffffff169063abb0517490602401600060405180830381865afa158015612723573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612769919081019061526c565b6006546040517f1d7cc84c00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690631d7cc84c906127c490879086908690600401615368565b600060405180830381865afa1580156127e1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526128279190810190615446565b949350505050565b600461283a81612ac7565b6000829003612875576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b828110156124b9576128a38484838181106128955761289561547b565b90506020020135600061362b565b806128ad816150bf565b915050612878565b60016128c081612ac7565b73ffffffffffffffffffffffffffffffffffffffff821661290d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527fe6a0768bc7cc02a7502c4e06cdb639aca06180fd05c4e57dddea1b2d1b0e8c0b9101611673565b6129946133ee565b63389a75e1600c52806000526020600c2080544211156129bc57636f5e88186000526004601cfd5b60009055610efe81613ca4565b6129d16133ee565b8060601b6129e757637448fbae6000526004601cfd5b610efe81613ca4565b60016129fb81612ac7565b73ffffffffffffffffffffffffffffffffffffffff8216612a48576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f0e526d19ade983f559120a81facf2b8e21a6f2e21c39c5a81a1ba1ee167b11cf9101611673565b638b78c6d8600c5233600052806020600c205416610efe576382b429006000526004601cfd5b600354604080517f05587775000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff16916305587775916004808301926020929190829003018187875af1158015612b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8291906154aa565b90506000612bae7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405490565b905060005b848110156112a8576000612bc782846154c3565b90506000878784818110612bdd57612bdd61547b565b600480546040517fabb051740000000000000000000000000000000000000000000000000000000081526020939093029490940135908201819052935060009273ffffffffffffffffffffffffffffffffffffffff16915063abb0517490602401600060405180830381865afa158015612c5b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612ca1919081019061526c565b90506000612cd06040518060800160405280600081526020016000815260200160008152602001600081525090565b612cd861472f565b600284604001516002811115612cf057612cf0614b7c565b03612d285783606001519250604051806080016040528060008152602001600081526020016000815260200160008152509150612de8565b612d32898b613fa7565b9250612d43838560a001518b614039565b60055460c08601516040517f85ffd98000000000000000000000000000000000000000000000000000000000815292945073ffffffffffffffffffffffffffffffffffffffff909116916385ffd98091612da4918791908e906004016154d6565b606060405180830381865afa158015612dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de59190615506565b90505b60006040518061012001604052808781526020016002600089815260200190815260200160002060008154612e1c906150bf565b91905081905581526020016001815260200186604001516002811115612e4457612e44614b7c565b8152602001856006811115612e5b57612e5b614b7c565b8152602001866080015161ffff1681526020018481526020018660c0015181526020018381525090508060008089815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff02191690836002811115612edf57612edf614b7c565b021790555060808201516003820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100836006811115612f2657612f26614b7c565b021790555060a082015160038201805461ffff90921662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff90921691909117905560c082015180516004830155602080820151600584015560408201516006840155606090910151600783015560e08301518051612fae926008850192019061474d565b50610100820151612fc590600983019060036147f6565b50905050867f63484ddf7bc40f724bda4e6e22ae36a82d00de48f05f341ba4ae15a93f6e435a82604051612ff99190614cf5565b60405180910390a260408051602081018c9052016040516020818303038152906040528051906020012060001c995050505050505050808061303a906150bf565b915050612bb3565b7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4054600082900361309f576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c456020908152604080832080546801000000000000000188020190558483527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4490915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b81811461319957808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600101613161565b50816000036131d4576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405550505050565b60008160011115801561322f57507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405482105b8015610bbc57505060009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260409020547c0100000000000000000000000000000000000000000000000000000000161590565b600061329383611acc565b90508115613341573373ffffffffffffffffffffffffffffffffffffffff8216146133415773ffffffffffffffffffffffffffffffffffffffff811660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832033845290915290205460ff16613341576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c46602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b610dba82826000614253565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611c5a576382b429006000526004601cfd5b610dba82826001614253565b60008160011161354f575060008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c446020526040812054907c01000000000000000000000000000000000000000000000000000000008216900361354f578060000361354a577f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405482106134f2576040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c44602052604090205480156134f2575b919050565b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405160019083600052602083015160405260408351036135d657604083015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166060526135fc565b60418351036135f757606083015160001a60205260408301516060526135fc565b600091505b6020600160806000855afa5191503d61361d57638baa579f6000526004601cfd5b600060605260405292915050565b600061363683613430565b9050806000806136738660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c466020526040902080549091565b91509150841561371557613688818433610fbb565b6137155773ffffffffffffffffffffffffffffffffffffffff831660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832033845290915290205460ff16613715576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801561372057600082555b73ffffffffffffffffffffffffffffffffffffffff831660008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c456020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b177c03000000000000000000000000000000000000000000000000000000001760008781527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260408120919091557c020000000000000000000000000000000000000000000000000000000085169003613888576001860160008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260408120549003613886577f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405481146138865760008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c44602052604090208590555b505b604051869060009073ffffffffffffffffffffffffffffffffffffffff8616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a450507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c418054600101905550505050565b6139056146a0565b60408083015160009081526001602081815291839020835160808101855281548082529282015493810193909352600281015493830193909352600390920154606082015260c0840151805191929161395f9083906154c3565b90525060208082015160c0850151909101805161397d9083906154c3565b90525060408082015160c0850151909101805161399b9083906154c3565b90525060608082015160c085015190910180516139b99083906154c3565b90525060c0830151606001516063106139da578260c00151606001516139dd565b60635b60c0840151606001525090919050565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480613aba57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16613aa17f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b15611c5a576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001610dba81612ac7565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613b81575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252613b7e918101906154aa565b60015b613bcf576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401611dc4565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114613c2b576040517faa1d49a400000000000000000000000000000000000000000000000000000000815260048101829052602401611dc4565b61182683836142ac565b3073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c5a576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff16613dc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e747261637460448201527f206973206e6f7420696e697469616c697a696e670000000000000000000000006064820152608401611dc4565b610dba828261430f565b73ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6040517f150b7a0200000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290613e89903390899088908890600401615584565b6020604051808303816000875af1925050508015613ee2575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252613edf918101906155cd565b60015b613f59573d808015613f10576040519150601f19603f3d011682016040523d82523d6000602084013e613f15565b606091505b508051600003613f51576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149050949350505050565b600080613fb6612710856155ea565b613fc19060016154c3565b90506000805b600681101561403057848160068110613fe257613fe261547b565b602002013582613ff291906154c3565b915081831161401e576140068160016154c3565b600681111561401757614017614b7c565b9350614030565b80614028816150bf565b915050613fc7565b50505092915050565b6140646040518060800160405280600081526020016000815260200160008152602001600081525090565b6000600185600681111561407a5761407a614b7c565b61408491906150f7565b61408f906020615625565b77640af253320aa333140a53220a0a44110a0a33110a0a2211901c905060018316156000816140c257601883901c6140c8565b601083901c5b905060006140d960ff8316876155ea565b6140e49060016154c3565b9050826140fd5786516140f89082906154c3565b61410a565b865161410a9082906150f7565b8552600186811c161592508261412457600c84901c61412a565b600884901c5b9150614139600f8316876155ea565b6141449060016154c3565b9050826141605780876020015161415b91906154c3565b614170565b80876020015161417091906150f7565b60208601526001600287901c161592508261418f57600c84901c614195565b600884901c5b91506141a4600f8316876155ea565b6141af9060016154c3565b9050826141cb578087604001516141c691906154c3565b6141db565b8087604001516141db91906150f7565b60408601526001600387901c16159250826141fa57600484901c6141fc565b835b915061420b600f8316876155ea565b6142169060016154c3565b9050826142325780876060015161422d91906154c3565b614242565b80876060015161424291906150f7565b606086015250929695505050505050565b638b78c6d8600c52826000526020600c20805483811783614275575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b6142b582614445565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115614307576118268282614514565b610dba614597565b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff166143c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e747261637460448201527f206973206e6f7420696e697469616c697a696e670000000000000000000000006064820152608401611dc4565b7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c426143f08382615682565b507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4361441c8282615682565b5060017f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c40555050565b8073ffffffffffffffffffffffffffffffffffffffff163b6000036144ae576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611dc4565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60606000808473ffffffffffffffffffffffffffffffffffffffff168460405161453e919061579c565b600060405180830381855af49150503d8060008114614579576040519150601f19603f3d011682016040523d82523d6000602084013e61457e565b606091505b509150915061458e8583836145cf565b95945050505050565b3415611c5a576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060826145e4576145df8261465e565b611a3f565b8151158015614608575073ffffffffffffffffffffffffffffffffffffffff84163b155b15614657576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401611dc4565b5080611a3f565b80511561466e5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101200160405280600081526020016000815260200160008152602001600060028111156146d4576146d4614b7c565b815260200160008152602001600061ffff1681526020016147166040518060800160405280600081526020016000815260200160008152602001600081525090565b81526020016060815260200161472a61472f565b905290565b60405180606001604052806003906020820280368337509192915050565b82805482825590600052602060002090600f016010900481019282156147e65791602002820160005b838211156147b657835183826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302614776565b80156147e45782816101000a81549061ffff02191690556002016020816001010492830192600103026147b6565b505b506147f2929150614824565b5090565b82600381019282156147e6579160200282015b828111156147e6578251825591602001919060010190614809565b5b808211156147f25760008155600101614825565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610efe57600080fd5b60006020828403121561487957600080fd5b8135611a3f81614839565b60008083601f84011261489657600080fd5b50813567ffffffffffffffff8111156148ae57600080fd5b6020830191508360208260051b85010111156148c957600080fd5b9250929050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461354a57600080fd5b600080600080610100858703121561490b57600080fd5b843567ffffffffffffffff81111561492257600080fd5b61492e87828801614884565b90955093505060e085018681111561494557600080fd5b602086019250614954816148d0565b91505092959194509250565b60005b8381101561497b578181015183820152602001614963565b50506000910152565b6000815180845261499c816020860160208601614960565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611a3f6020830184614984565b6000602082840312156149f357600080fd5b5035919050565b60008060408385031215614a0d57600080fd5b614a16836148d0565b946020939093013593505050565b60008082840360a0811215614a3857600080fd5b8335925060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082011215614a6c57600080fd5b506020830190509250929050565b600080600060608486031215614a8f57600080fd5b614a98846148d0565b9250614aa6602085016148d0565b9150604084013590509250925092565b60008060008060608587031215614acc57600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115614af257600080fd5b818701915087601f830112614b0657600080fd5b813581811115614b1557600080fd5b886020828501011115614b2757600080fd5b95989497505060200194505050565b600060208284031215614b4857600080fd5b611a3f826148d0565b8151815260208083015190820152604080830151908201526060808301519082015260808101610bbc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110614bbb57614bbb614b7c565b9052565b60078110614bbb57614bbb614b7c565b600081518084526020808501945080840160005b83811015614c0357815161ffff1687529582019590820190600101614be3565b509495945050505050565b8060005b60038110156124b9578151845260209384019390910190600101614c12565b60006101c08251845260208301516020850152604083015160408501526060830151614c606060860182614bab565b506080830151614c736080860182614bbf565b5060a0830151614c8960a086018261ffff169052565b5060c0830151614cbd60c0860182805182526020810151602083015260408101516040830152606081015160608301525050565b5060e083015181610140860152614cd682860182614bcf565b915050610100830151614ced610160860182614c0e565b509392505050565b602081526000611a3f6020830184614c31565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614d5a57614d5a614d08565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614da757614da7614d08565b604052919050565b600067ffffffffffffffff821115614dc957614dc9614d08565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112614e0657600080fd5b8135614e19614e1482614daf565b614d60565b818152846020838601011115614e2e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614e5e57600080fd5b614e67836148d0565b9150602083013567ffffffffffffffff811115614e8357600080fd5b614e8f85828601614df5565b9150509250929050565b600080600080600080600080610100898b031215614eb657600080fd5b614ebf896148d0565b9750614ecd60208a016148d0565b9650614edb60408a016148d0565b9550614ee960608a016148d0565b9450614ef760808a016148d0565b9350614f0560a08a016148d0565b9250614f1360c08a016148d0565b9150614f2160e08a016148d0565b90509295985092959890939650565b60008060408385031215614f4357600080fd5b614f4c836148d0565b915060208301358015158114614f6157600080fd5b809150509250929050565b60008060008060808587031215614f8257600080fd5b614f8b856148d0565b9350614f99602086016148d0565b925060408501359150606085013567ffffffffffffffff811115614fbc57600080fd5b61495487828801614df5565b60008060208385031215614fdb57600080fd5b823567ffffffffffffffff811115614ff257600080fd5b614ffe85828601614884565b90969095509350505050565b6000806040838503121561501d57600080fd5b615026836148d0565b9150615034602084016148d0565b90509250929050565b600181811c9082168061505157607f821691505b60208210810361508a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036150f0576150f0615090565b5060010190565b81810381811115610bbc57610bbc615090565b600082601f83011261511b57600080fd5b8151615129614e1482614daf565b81815284602083860101111561513e57600080fd5b612827826020830160208701614960565b80516003811061354a57600080fd5b80516007811061354a57600080fd5b805161ffff8116811461354a57600080fd5b60006080828403121561519157600080fd5b6040516080810181811067ffffffffffffffff821117156151b4576151b4614d08565b8060405250809150825181526020830151602082015260408301516040820152606083015160608201525092915050565b600082601f8301126151f657600080fd5b8151602067ffffffffffffffff82111561521257615212614d08565b8160051b615221828201614d60565b928352848101820192828101908785111561523b57600080fd5b83870192505b84831015615261576152528361516d565b82529183019190830190615241565b979650505050505050565b60006020828403121561527e57600080fd5b815167ffffffffffffffff8082111561529657600080fd5b9083019061014082860312156152ab57600080fd5b6152b3614d37565b8251828111156152c257600080fd5b6152ce8782860161510a565b8252506020830151828111156152e357600080fd5b6152ef8782860161510a565b6020830152506153016040840161514f565b60408201526153126060840161515e565b60608201526153236080840161516d565b60808201526153358660a0850161517f565b60a08201526101208301518281111561534d57600080fd5b615359878286016151e5565b60c08301525095945050505050565b8381526060602082015260006153816060830185614c31565b8281036040840152610140845181835261539d82840182614984565b915050602085015182820360208401526153b78282614984565b91505060408501516153cc6040840182614bab565b5060608501516153df6060840182614bbf565b5061ffff608086015116608083015260a085015161542160a0840182805182526020810151602083015260408101516040830152606081015160608301525050565b5060c085015182820361012084015261543a8282614bcf565b98975050505050505050565b60006020828403121561545857600080fd5b815167ffffffffffffffff81111561546f57600080fd5b6128278482850161510a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156154bc57600080fd5b5051919050565b80820180821115610bbc57610bbc615090565b6154e08185614bbf565b6060602082015260006154f66060830185614bcf565b9050826040830152949350505050565b60006060828403121561551857600080fd5b82601f83011261552757600080fd5b6040516060810181811067ffffffffffffffff8211171561554a5761554a614d08565b60405280606084018581111561555f57600080fd5b845b81811015615579578051835260209283019201615561565b509195945050505050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526155c36080830184614984565b9695505050505050565b6000602082840312156155df57600080fd5b8151611a3f81614839565b600082615620577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b8082028115828204841417610bbc57610bbc615090565b601f82111561182657600081815260208120601f850160051c810160208610156156635750805b601f850160051c820191505b818110156112a85782815560010161566f565b815167ffffffffffffffff81111561569c5761569c614d08565b6156b0816156aa845461503d565b8461563c565b602080601f83116001811461570357600084156156cd5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556112a8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561575057888601518255948401946001909101908401615731565b508582101561578c57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600082516157ae818460208701614960565b919091019291505056fea264697066735822122042b927aed7d8d8055563b8cab511d4bfd90bad06a40144e9dac0c24adb3d246364736f6c63430008140033
Deployed Bytecode
0x60806040526004361061033f5760003560e01c806354d1f13d116101b057806397d75776116100ec578063d50b31eb11610095578063f04e283e1161006f578063f04e283e14610a64578063f2fde38b14610a77578063fd4fe8a814610a8a578063fee81cf414610aaa57600080fd5b8063d50b31eb146109a2578063e0a04d71146109c2578063e985e9c5146109ef57600080fd5b8063b88d4fde116100c6578063b88d4fde1461094f578063c87b56dd14610962578063cf46fd011461098257600080fd5b806397d75776146108b2578063a22cb465146108e6578063ad3cb1cc1461090657600080fd5b8063715018a61161015957806381fbd3291161013357806381fbd3291461081c5780638a29e2de146108495780638da5cb5b1461086957806395d89b411461089d57600080fd5b8063715018a6146107c75780637a7932f5146107cf5780637afb9b1d146107ef57600080fd5b80636c19e7831161018a5780636c19e7831461075a578063703199701461077a57806370a08231146107a757600080fd5b806354d1f13d146107055780636352211e1461070d578063684931ed1461072d57600080fd5b8063256929621161027f57806342842e0e116102285780634dc0884f116102025780634dc0884f146106795780634f1ef286146106a6578063514e62fc146106b957806352d1902d146106f057600080fd5b806342842e0e1461063357806342966c68146106465780634a4ee7b11461066657600080fd5b806332e12cb91161025957806332e12cb9146105c657806335022122146105e65780633ec565081461061357600080fd5b8063256929621461056b578063295bbecd146105735780632de948071461059357600080fd5b806318160ddd116102ec5780631cd64df4116102c65780631cd64df4146104de578063238ac9331461051557806323b872dd1461054257806323f849701461055557600080fd5b806318160ddd14610435578063183a4f6e146104b85780631c10893f146104cb57600080fd5b8063081812fc1161031d578063081812fc146103bd578063095ea7b31461040257806311e2dc9b1461041557600080fd5b806301ffc9a71461034457806303728ca31461037957806306fdde031461039b575b600080fd5b34801561035057600080fd5b5061036461035f366004614867565b610add565b60405190151581526020015b60405180910390f35b34801561038557600080fd5b506103996103943660046148f4565b610bc2565b005b3480156103a757600080fd5b506103b0610c71565b60405161037091906149ce565b3480156103c957600080fd5b506103dd6103d83660046149e1565b610d25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610370565b6103996104103660046149fa565b610dae565b34801561042157600080fd5b50610399610430366004614a24565b610dbe565b34801561044157600080fd5b507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c41547f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4054037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b604051908152602001610370565b6103996104c63660046149e1565b610ef4565b6103996104d93660046149fa565b610f01565b3480156104ea57600080fd5b506103646104f93660046149fa565b638b78c6d8600c90815260009290925260209091205481161490565b34801561052157600080fd5b506007546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b610399610550366004614a7a565b610f13565b34801561056157600080fd5b506104aa60085481565b6103996112b0565b34801561057f57600080fd5b5061039961058e366004614ab6565b611300565b34801561059f57600080fd5b506104aa6105ae366004614b36565b638b78c6d8600c908152600091909152602090205490565b3480156105d257600080fd5b506103996105e1366004614b36565b6115a0565b3480156105f257600080fd5b506106066106013660046149e1565b611680565b6040516103709190614b51565b34801561061f57600080fd5b5061039961062e366004614b36565b611734565b610399610641366004614a7a565b61180b565b34801561065257600080fd5b506103996106613660046149e1565b61182b565b6103996106743660046149fa565b611836565b34801561068557600080fd5b506106996106943660046149e1565b611848565b6040516103709190614cf5565b6103996106b4366004614e4b565b611a46565b3480156106c557600080fd5b506103646106d43660046149fa565b638b78c6d8600c90815260009290925260209091205416151590565b3480156106fc57600080fd5b506104aa611a61565b610399611a90565b34801561071957600080fd5b506103dd6107283660046149e1565b611acc565b34801561073957600080fd5b506003546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561076657600080fd5b50610399610775366004614b36565b611ad7565b34801561078657600080fd5b506006546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107b357600080fd5b506104aa6107c2366004614b36565b611ba7565b610399611c48565b3480156107db57600080fd5b506103996107ea3660046149e1565b611c5c565b3480156107fb57600080fd5b506004546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561082857600080fd5b506104aa6108373660046149e1565b60026020526000908152604090205481565b34801561085557600080fd5b50610399610864366004614e99565b611cdf565b34801561087557600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546103dd565b3480156108a957600080fd5b506103b0612368565b3480156108be57600080fd5b506103dd7f000000000000000000000000430000000000000000000000000000000000000281565b3480156108f257600080fd5b50610399610901366004614f30565b612399565b34801561091257600080fd5b506103b06040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b61039961095d366004614f6c565b61244f565b34801561096e57600080fd5b506103b061097d3660046149e1565b6124bf565b34801561098e57600080fd5b5061039961099d366004614fc8565b61282f565b3480156109ae57600080fd5b506103996109bd366004614b36565b6128b5565b3480156109ce57600080fd5b506005546103dd9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109fb57600080fd5b50610364610a0a36600461500a565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832093909416825291909152205460ff1690565b610399610a72366004614b36565b61298c565b610399610a85366004614b36565b6129c9565b348015610a9657600080fd5b50610399610aa5366004614b36565b6129f0565b348015610ab657600080fd5b506104aa610ac5366004614b36565b63389a75e1600c908152600091909152602090205490565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610b7057507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610bbc57507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6004610bcd81612ac7565b6000849003610c08576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610c55576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c60858585612aed565b610c6a8285613042565b5050505050565b60607f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c406002018054610ca29061503d565b80601f0160208091040260200160405190810160405280929190818152602001828054610cce9061503d565b8015610d1b5780601f10610cf057610100808354040283529160200191610d1b565b820191906000526020600020905b815481529060010190602001808311610cfe57829003601f168201915b5050505050905090565b6000610d30826131fc565b610d66576040517fcf4700e400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c46602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b610dba82826001613288565b5050565b6001610dc981612ac7565b600183111580610dda575060085483115b15610e11576040517f7601ab6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260016020818152604080842081516080810183528154815281850180548286015260028301805483860152600384018054606080860191909152988c905296865289358455948901359055918701359092559285013590915550837f74d75c7983755f1c284547da8f27cd36cb59934a29590b598cea9b9810f04cc08285604051610ee692919082518152602080840151818301526040808501518184015260609485015185840152833560808401529083013560a083015282013560c082015291013560e08201526101000190565b60405180910390a250505050565b610efe33826133e2565b50565b610f096133ee565b610dba8282613424565b6000610f1e82613430565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610f85576040517fa114810000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c46602052604090208054610fdd8187335b73ffffffffffffffffffffffffffffffffffffffff9081169116811491141790565b61106a5773ffffffffffffffffffffffffffffffffffffffff861660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832033845290915290205460ff1661106a576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85166110b7576040517fea553b3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156110c257600082555b73ffffffffffffffffffffffffffffffffffffffff86811660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c45602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055918716808252919020805460010190554260a01b177c02000000000000000000000000000000000000000000000000000000001760008581527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260408120919091557c02000000000000000000000000000000000000000000000000000000008416900361124c576001840160008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c446020526040812054900361124a577f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4054811461124a5760008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c44602052604090208490555b505b838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45b505050505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b611309846131fc565b61133f576040517f96f1504a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61134884611acc565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146113ac576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008548311156113e8576040517f7601ab6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260208190526040812060020180548290611406906150bf565b91829055509050838114611446576040517f7c139f5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006114a88686604051602001611467929190918252602082015260400190565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b600754604080516020601f880181900481028201810190925286815292935073ffffffffffffffffffffffffffffffffffffffff9091169161150791879087908190840183828082843760009201919091525086939250506135819050565b73ffffffffffffffffffffffffffffffffffffffff1614611554576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b857f66833f6d7d7a01eaed9fb21eb9cc54f0fb9497fa9251a6c0773372c8d3e0aa0c6115816001856150f7565b60408051918252602082018690520160405180910390a2505050505050565b60016115ab81612ac7565b73ffffffffffffffffffffffffffffffffffffffff82166115f8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527fba77f4757246a5ae4182e908698755b395d9654a76ebe7623c8eba114dd7ebdf91015b60405180910390a1505050565b6116ab6040518060800160405280600081526020016000815260200160008152602001600081525090565b8115806116b9575060085482115b156116f0576040517f6e1e14c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000908152600160208181526040928390208351608081018552815481529281015491830191909152600281015492820192909252600390910154606082015290565b600161173f81612ac7565b73ffffffffffffffffffffffffffffffffffffffff821661178c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f35caef78b01a683ca840d6cd59416128819f56369fa6dc9049298a812a35e7039101611673565b6118268383836040518060200160405280600081525061244f565b505050565b610efe81600161362b565b61183e6133ee565b610dba82826133e2565b6118506146a0565b611859826131fc565b61188f576040517f96f1504a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260208181526040808320815161012081018352815481526001820154938101939093526002808201549284019290925260038101549091606084019160ff16908111156118e3576118e3614b7c565b60028111156118f4576118f4614b7c565b81526020016003820160019054906101000a900460ff16600681111561191c5761191c614b7c565b600681111561192d5761192d614b7c565b8152600382015462010000900461ffff166020808301919091526040805160808101825260048501548152600585015481840152600685015481830152600785015460608083019190915282850191909152600885018054835181860281018601909452808452919094019391928301828280156119f257602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116119b95790505b505050918352505060408051606081019182905260209092019190600984019060039082845b815481526020019060010190808311611a18575050505050815250509050611a3f816138fd565b9392505050565b611a4e6139ed565b611a5782613af1565b610dba8282613afc565b6000611a6b613c35565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6000610bbc82613430565b6001611ae281612ac7565b73ffffffffffffffffffffffffffffffffffffffff8216611b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb90600090a3505050565b600073ffffffffffffffffffffffffffffffffffffffff8216611bf6576040517f8f4eb60400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff1660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c45602052604090205467ffffffffffffffff1690565b611c506133ee565b611c5a6000613ca4565b565b6001611c6781612ac7565b81600003611ca1576040517f6e1e14c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600880549083905560408051828152602081018590527f92d27f4a98ff8c3157777f442f548d5615527466d86e12b028b7744e6ffbc2799101611673565b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff16611d38577fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f5460ff1615611d3c565b303b155b611dcd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e747261637460448201527f20697320616c726561647920696e697469616c697a656400000000000000000060648201526084015b60405180910390fd5b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff16158015611e4a577fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015611e955750825b905060008267ffffffffffffffff166001148015611eb25750303b155b905081158015611ec0575080155b15611ef7576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315611f585784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff8e161580611f8f575073ffffffffffffffffffffffffffffffffffffffff8d16155b80611fae575073ffffffffffffffffffffffffffffffffffffffff8c16155b80611fcd575073ffffffffffffffffffffffffffffffffffffffff8b16155b80611fec575073ffffffffffffffffffffffffffffffffffffffff8a16155b8061200b575073ffffffffffffffffffffffffffffffffffffffff8916155b8061202a575073ffffffffffffffffffffffffffffffffffffffff8816155b80612049575073ffffffffffffffffffffffffffffffffffffffff8716155b15612080576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff16634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156120e857600080fd5b505af11580156120fc573d6000803e3d6000fd5b50506040517feb86469800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301527f000000000000000000000000430000000000000000000000000000000000000216925063eb8646989150602401600060405180830381600087803b15801561218957600080fd5b505af115801561219d573d6000803e3d6000fd5b505050506122156040518060400160405280600a81526020017f47616d65204361726473000000000000000000000000000000000000000000008152506040518060400160405280600581526020017f4341524453000000000000000000000000000000000000000000000000000000815250613d0a565b61221e8e613dca565b6122298d6001613424565b600780547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8f811691909117909255600a6008556003805482168e84161790556004805482168d84161790556005805482168c841617905560068054909116918a16919091179055831561230a5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050801561235d577fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b505050505050505050565b60607f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c406003018054610ca29061503d565b3360008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b61245a848484610f13565b73ffffffffffffffffffffffffffffffffffffffff83163b156124b95761248384848484613e2e565b6124b9576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60606124ca826131fc565b612500576040517f96f1504a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260208181526040808320815161012081018352815481526001820154938101939093526002808201549284019290925260038101549091606084019160ff169081111561255457612554614b7c565b600281111561256557612565614b7c565b81526020016003820160019054906101000a900460ff16600681111561258d5761258d614b7c565b600681111561259e5761259e614b7c565b8152600382015462010000900461ffff1660208083019190915260408051608081018252600485015481526005850154818401526006850154818301526007850154606080830191909152828501919091526008850180548351818602810186019094528084529190940193919283018282801561266357602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161262a5790505b505050918352505060408051606081019182905260209092019190600984019060039082845b8154815260200190600101908083116126895750505050508152505090506126b0816138fd565b6004805482516040517fabb051740000000000000000000000000000000000000000000000000000000081529283015291925060009173ffffffffffffffffffffffffffffffffffffffff169063abb0517490602401600060405180830381865afa158015612723573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612769919081019061526c565b6006546040517f1d7cc84c00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690631d7cc84c906127c490879086908690600401615368565b600060405180830381865afa1580156127e1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526128279190810190615446565b949350505050565b600461283a81612ac7565b6000829003612875576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b828110156124b9576128a38484838181106128955761289561547b565b90506020020135600061362b565b806128ad816150bf565b915050612878565b60016128c081612ac7565b73ffffffffffffffffffffffffffffffffffffffff821661290d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527fe6a0768bc7cc02a7502c4e06cdb639aca06180fd05c4e57dddea1b2d1b0e8c0b9101611673565b6129946133ee565b63389a75e1600c52806000526020600c2080544211156129bc57636f5e88186000526004601cfd5b60009055610efe81613ca4565b6129d16133ee565b8060601b6129e757637448fbae6000526004601cfd5b610efe81613ca4565b60016129fb81612ac7565b73ffffffffffffffffffffffffffffffffffffffff8216612a48576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f0e526d19ade983f559120a81facf2b8e21a6f2e21c39c5a81a1ba1ee167b11cf9101611673565b638b78c6d8600c5233600052806020600c205416610efe576382b429006000526004601cfd5b600354604080517f05587775000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff16916305587775916004808301926020929190829003018187875af1158015612b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8291906154aa565b90506000612bae7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405490565b905060005b848110156112a8576000612bc782846154c3565b90506000878784818110612bdd57612bdd61547b565b600480546040517fabb051740000000000000000000000000000000000000000000000000000000081526020939093029490940135908201819052935060009273ffffffffffffffffffffffffffffffffffffffff16915063abb0517490602401600060405180830381865afa158015612c5b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612ca1919081019061526c565b90506000612cd06040518060800160405280600081526020016000815260200160008152602001600081525090565b612cd861472f565b600284604001516002811115612cf057612cf0614b7c565b03612d285783606001519250604051806080016040528060008152602001600081526020016000815260200160008152509150612de8565b612d32898b613fa7565b9250612d43838560a001518b614039565b60055460c08601516040517f85ffd98000000000000000000000000000000000000000000000000000000000815292945073ffffffffffffffffffffffffffffffffffffffff909116916385ffd98091612da4918791908e906004016154d6565b606060405180830381865afa158015612dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de59190615506565b90505b60006040518061012001604052808781526020016002600089815260200190815260200160002060008154612e1c906150bf565b91905081905581526020016001815260200186604001516002811115612e4457612e44614b7c565b8152602001856006811115612e5b57612e5b614b7c565b8152602001866080015161ffff1681526020018481526020018660c0015181526020018381525090508060008089815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a81548160ff02191690836002811115612edf57612edf614b7c565b021790555060808201516003820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100836006811115612f2657612f26614b7c565b021790555060a082015160038201805461ffff90921662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff90921691909117905560c082015180516004830155602080820151600584015560408201516006840155606090910151600783015560e08301518051612fae926008850192019061474d565b50610100820151612fc590600983019060036147f6565b50905050867f63484ddf7bc40f724bda4e6e22ae36a82d00de48f05f341ba4ae15a93f6e435a82604051612ff99190614cf5565b60405180910390a260408051602081018c9052016040516020818303038152906040528051906020012060001c995050505050505050808061303a906150bf565b915050612bb3565b7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4054600082900361309f576040517fb562e8dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c456020908152604080832080546801000000000000000188020190558483527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4490915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b81811461319957808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600101613161565b50816000036131d4576040517f2e07630000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405550505050565b60008160011115801561322f57507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405482105b8015610bbc57505060009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260409020547c0100000000000000000000000000000000000000000000000000000000161590565b600061329383611acc565b90508115613341573373ffffffffffffffffffffffffffffffffffffffff8216146133415773ffffffffffffffffffffffffffffffffffffffff811660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832033845290915290205460ff16613341576040517fcfb3b94200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c46602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88811691821790925591518693918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a450505050565b610dba82826000614253565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611c5a576382b429006000526004601cfd5b610dba82826001614253565b60008160011161354f575060008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c446020526040812054907c01000000000000000000000000000000000000000000000000000000008216900361354f578060000361354a577f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405482106134f2576040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c44602052604090205480156134f2575b919050565b6040517fdf2d9b4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405160019083600052602083015160405260408351036135d657604083015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166060526135fc565b60418351036135f757606083015160001a60205260408301516060526135fc565b600091505b6020600160806000855afa5191503d61361d57638baa579f6000526004601cfd5b600060605260405292915050565b600061363683613430565b9050806000806136738660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c466020526040902080549091565b91509150841561371557613688818433610fbb565b6137155773ffffffffffffffffffffffffffffffffffffffff831660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020908152604080832033845290915290205460ff16613715576040517f59c896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801561372057600082555b73ffffffffffffffffffffffffffffffffffffffff831660008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c456020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b177c03000000000000000000000000000000000000000000000000000000001760008781527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260408120919091557c020000000000000000000000000000000000000000000000000000000085169003613888576001860160008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4460205260408120549003613886577f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c405481146138865760008181527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c44602052604090208590555b505b604051869060009073ffffffffffffffffffffffffffffffffffffffff8616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a450507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c418054600101905550505050565b6139056146a0565b60408083015160009081526001602081815291839020835160808101855281548082529282015493810193909352600281015493830193909352600390920154606082015260c0840151805191929161395f9083906154c3565b90525060208082015160c0850151909101805161397d9083906154c3565b90525060408082015160c0850151909101805161399b9083906154c3565b90525060608082015160c085015190910180516139b99083906154c3565b90525060c0830151606001516063106139da578260c00151606001516139dd565b60635b60c0840151606001525090919050565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007a0e380c999c17e03edbd00b1b2c6bee9e1877cf161480613aba57507f0000000000000000000000007a0e380c999c17e03edbd00b1b2c6bee9e1877cf73ffffffffffffffffffffffffffffffffffffffff16613aa17f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b15611c5a576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001610dba81612ac7565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613b81575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252613b7e918101906154aa565b60015b613bcf576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401611dc4565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114613c2b576040517faa1d49a400000000000000000000000000000000000000000000000000000000815260048101829052602401611dc4565b61182683836142ac565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007a0e380c999c17e03edbd00b1b2c6bee9e1877cf1614611c5a576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff16613dc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e747261637460448201527f206973206e6f7420696e697469616c697a696e670000000000000000000000006064820152608401611dc4565b610dba828261430f565b73ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6040517f150b7a0200000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290613e89903390899088908890600401615584565b6020604051808303816000875af1925050508015613ee2575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252613edf918101906155cd565b60015b613f59573d808015613f10576040519150601f19603f3d011682016040523d82523d6000602084013e613f15565b606091505b508051600003613f51576040517fd1a57ed600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149050949350505050565b600080613fb6612710856155ea565b613fc19060016154c3565b90506000805b600681101561403057848160068110613fe257613fe261547b565b602002013582613ff291906154c3565b915081831161401e576140068160016154c3565b600681111561401757614017614b7c565b9350614030565b80614028816150bf565b915050613fc7565b50505092915050565b6140646040518060800160405280600081526020016000815260200160008152602001600081525090565b6000600185600681111561407a5761407a614b7c565b61408491906150f7565b61408f906020615625565b77640af253320aa333140a53220a0a44110a0a33110a0a2211901c905060018316156000816140c257601883901c6140c8565b601083901c5b905060006140d960ff8316876155ea565b6140e49060016154c3565b9050826140fd5786516140f89082906154c3565b61410a565b865161410a9082906150f7565b8552600186811c161592508261412457600c84901c61412a565b600884901c5b9150614139600f8316876155ea565b6141449060016154c3565b9050826141605780876020015161415b91906154c3565b614170565b80876020015161417091906150f7565b60208601526001600287901c161592508261418f57600c84901c614195565b600884901c5b91506141a4600f8316876155ea565b6141af9060016154c3565b9050826141cb578087604001516141c691906154c3565b6141db565b8087604001516141db91906150f7565b60408601526001600387901c16159250826141fa57600484901c6141fc565b835b915061420b600f8316876155ea565b6142169060016154c3565b9050826142325780876060015161422d91906154c3565b614242565b80876060015161424291906150f7565b606086015250929695505050505050565b638b78c6d8600c52826000526020600c20805483811783614275575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b6142b582614445565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115614307576118268282614514565b610dba614597565b7fee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85f54610100900460ff166143c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e747261637460448201527f206973206e6f7420696e697469616c697a696e670000000000000000000000006064820152608401611dc4565b7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c426143f08382615682565b507f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4361441c8282615682565b5060017f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c40555050565b8073ffffffffffffffffffffffffffffffffffffffff163b6000036144ae576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611dc4565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60606000808473ffffffffffffffffffffffffffffffffffffffff168460405161453e919061579c565b600060405180830381855af49150503d8060008114614579576040519150601f19603f3d011682016040523d82523d6000602084013e61457e565b606091505b509150915061458e8583836145cf565b95945050505050565b3415611c5a576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060826145e4576145df8261465e565b611a3f565b8151158015614608575073ffffffffffffffffffffffffffffffffffffffff84163b155b15614657576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401611dc4565b5080611a3f565b80511561466e5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101200160405280600081526020016000815260200160008152602001600060028111156146d4576146d4614b7c565b815260200160008152602001600061ffff1681526020016147166040518060800160405280600081526020016000815260200160008152602001600081525090565b81526020016060815260200161472a61472f565b905290565b60405180606001604052806003906020820280368337509192915050565b82805482825590600052602060002090600f016010900481019282156147e65791602002820160005b838211156147b657835183826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302614776565b80156147e45782816101000a81549061ffff02191690556002016020816001010492830192600103026147b6565b505b506147f2929150614824565b5090565b82600381019282156147e6579160200282015b828111156147e6578251825591602001919060010190614809565b5b808211156147f25760008155600101614825565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610efe57600080fd5b60006020828403121561487957600080fd5b8135611a3f81614839565b60008083601f84011261489657600080fd5b50813567ffffffffffffffff8111156148ae57600080fd5b6020830191508360208260051b85010111156148c957600080fd5b9250929050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461354a57600080fd5b600080600080610100858703121561490b57600080fd5b843567ffffffffffffffff81111561492257600080fd5b61492e87828801614884565b90955093505060e085018681111561494557600080fd5b602086019250614954816148d0565b91505092959194509250565b60005b8381101561497b578181015183820152602001614963565b50506000910152565b6000815180845261499c816020860160208601614960565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611a3f6020830184614984565b6000602082840312156149f357600080fd5b5035919050565b60008060408385031215614a0d57600080fd5b614a16836148d0565b946020939093013593505050565b60008082840360a0811215614a3857600080fd5b8335925060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082011215614a6c57600080fd5b506020830190509250929050565b600080600060608486031215614a8f57600080fd5b614a98846148d0565b9250614aa6602085016148d0565b9150604084013590509250925092565b60008060008060608587031215614acc57600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115614af257600080fd5b818701915087601f830112614b0657600080fd5b813581811115614b1557600080fd5b886020828501011115614b2757600080fd5b95989497505060200194505050565b600060208284031215614b4857600080fd5b611a3f826148d0565b8151815260208083015190820152604080830151908201526060808301519082015260808101610bbc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110614bbb57614bbb614b7c565b9052565b60078110614bbb57614bbb614b7c565b600081518084526020808501945080840160005b83811015614c0357815161ffff1687529582019590820190600101614be3565b509495945050505050565b8060005b60038110156124b9578151845260209384019390910190600101614c12565b60006101c08251845260208301516020850152604083015160408501526060830151614c606060860182614bab565b506080830151614c736080860182614bbf565b5060a0830151614c8960a086018261ffff169052565b5060c0830151614cbd60c0860182805182526020810151602083015260408101516040830152606081015160608301525050565b5060e083015181610140860152614cd682860182614bcf565b915050610100830151614ced610160860182614c0e565b509392505050565b602081526000611a3f6020830184614c31565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614d5a57614d5a614d08565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614da757614da7614d08565b604052919050565b600067ffffffffffffffff821115614dc957614dc9614d08565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112614e0657600080fd5b8135614e19614e1482614daf565b614d60565b818152846020838601011115614e2e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614e5e57600080fd5b614e67836148d0565b9150602083013567ffffffffffffffff811115614e8357600080fd5b614e8f85828601614df5565b9150509250929050565b600080600080600080600080610100898b031215614eb657600080fd5b614ebf896148d0565b9750614ecd60208a016148d0565b9650614edb60408a016148d0565b9550614ee960608a016148d0565b9450614ef760808a016148d0565b9350614f0560a08a016148d0565b9250614f1360c08a016148d0565b9150614f2160e08a016148d0565b90509295985092959890939650565b60008060408385031215614f4357600080fd5b614f4c836148d0565b915060208301358015158114614f6157600080fd5b809150509250929050565b60008060008060808587031215614f8257600080fd5b614f8b856148d0565b9350614f99602086016148d0565b925060408501359150606085013567ffffffffffffffff811115614fbc57600080fd5b61495487828801614df5565b60008060208385031215614fdb57600080fd5b823567ffffffffffffffff811115614ff257600080fd5b614ffe85828601614884565b90969095509350505050565b6000806040838503121561501d57600080fd5b615026836148d0565b9150615034602084016148d0565b90509250929050565b600181811c9082168061505157607f821691505b60208210810361508a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036150f0576150f0615090565b5060010190565b81810381811115610bbc57610bbc615090565b600082601f83011261511b57600080fd5b8151615129614e1482614daf565b81815284602083860101111561513e57600080fd5b612827826020830160208701614960565b80516003811061354a57600080fd5b80516007811061354a57600080fd5b805161ffff8116811461354a57600080fd5b60006080828403121561519157600080fd5b6040516080810181811067ffffffffffffffff821117156151b4576151b4614d08565b8060405250809150825181526020830151602082015260408301516040820152606083015160608201525092915050565b600082601f8301126151f657600080fd5b8151602067ffffffffffffffff82111561521257615212614d08565b8160051b615221828201614d60565b928352848101820192828101908785111561523b57600080fd5b83870192505b84831015615261576152528361516d565b82529183019190830190615241565b979650505050505050565b60006020828403121561527e57600080fd5b815167ffffffffffffffff8082111561529657600080fd5b9083019061014082860312156152ab57600080fd5b6152b3614d37565b8251828111156152c257600080fd5b6152ce8782860161510a565b8252506020830151828111156152e357600080fd5b6152ef8782860161510a565b6020830152506153016040840161514f565b60408201526153126060840161515e565b60608201526153236080840161516d565b60808201526153358660a0850161517f565b60a08201526101208301518281111561534d57600080fd5b615359878286016151e5565b60c08301525095945050505050565b8381526060602082015260006153816060830185614c31565b8281036040840152610140845181835261539d82840182614984565b915050602085015182820360208401526153b78282614984565b91505060408501516153cc6040840182614bab565b5060608501516153df6060840182614bbf565b5061ffff608086015116608083015260a085015161542160a0840182805182526020810151602083015260408101516040830152606081015160608301525050565b5060c085015182820361012084015261543a8282614bcf565b98975050505050505050565b60006020828403121561545857600080fd5b815167ffffffffffffffff81111561546f57600080fd5b6128278482850161510a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156154bc57600080fd5b5051919050565b80820180821115610bbc57610bbc615090565b6154e08185614bbf565b6060602082015260006154f66060830185614bcf565b9050826040830152949350505050565b60006060828403121561551857600080fd5b82601f83011261552757600080fd5b6040516060810181811067ffffffffffffffff8211171561554a5761554a614d08565b60405280606084018581111561555f57600080fd5b845b81811015615579578051835260209283019201615561565b509195945050505050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250836040830152608060608301526155c36080830184614984565b9695505050505050565b6000602082840312156155df57600080fd5b8151611a3f81614839565b600082615620577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b8082028115828204841417610bbc57610bbc615090565b601f82111561182657600081815260208120601f850160051c810160208610156156635750805b601f850160051c820191505b818110156112a85782815560010161566f565b815167ffffffffffffffff81111561569c5761569c614d08565b6156b0816156aa845461503d565b8461563c565b602080601f83116001811461570357600084156156cd5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556112a8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561575057888601518255948401946001909101908401615731565b508582101561578c57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600082516157ae818460208701614960565b919091019291505056fea264697066735822122042b927aed7d8d8055563b8cab511d4bfd90bad06a40144e9dac0c24adb3d246364736f6c63430008140033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.