Source Code
Latest 25 from a total of 4,505 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Pause | 11371298 | 437 days ago | IN | 0 ETH | 0.00000021 | ||||
| Withdraw Glory | 11371187 | 437 days ago | IN | 0 ETH | 0.0000002 | ||||
| Claim Specific U... | 8860744 | 495 days ago | IN | 0 ETH | 0.00000359 | ||||
| Claim Unit Card | 8851561 | 495 days ago | IN | 0 ETH | 0.0000046 | ||||
| Claim Pack | 8851552 | 495 days ago | IN | 0 ETH | 0.00000068 | ||||
| Claim Unit Card | 8851538 | 495 days ago | IN | 0 ETH | 0.00000491 | ||||
| Claim Pack | 8851529 | 495 days ago | IN | 0 ETH | 0.00000069 | ||||
| Claim Specific U... | 8851516 | 495 days ago | IN | 0 ETH | 0.00000421 | ||||
| Claim Pack | 8851499 | 495 days ago | IN | 0 ETH | 0.00000084 | ||||
| Claim Pack | 8851487 | 495 days ago | IN | 0 ETH | 0.00000084 | ||||
| Claim Specific U... | 8851477 | 495 days ago | IN | 0 ETH | 0.00000457 | ||||
| Claim Specific U... | 8851463 | 495 days ago | IN | 0 ETH | 0.00000476 | ||||
| Claim Specific U... | 8851452 | 495 days ago | IN | 0 ETH | 0.00000468 | ||||
| Claim Specific U... | 8851433 | 495 days ago | IN | 0 ETH | 0.00000463 | ||||
| Buy Battle Pass | 8851425 | 495 days ago | IN | 0 ETH | 0.00011752 | ||||
| Claim Unit Card | 8851023 | 495 days ago | IN | 0 ETH | 0.00000455 | ||||
| Claim Pack | 8851007 | 495 days ago | IN | 0 ETH | 0.00000068 | ||||
| Claim Unit Card | 8850994 | 495 days ago | IN | 0 ETH | 0.00000482 | ||||
| Claim Pack | 8850982 | 495 days ago | IN | 0 ETH | 0.00000069 | ||||
| Claim Specific U... | 8850967 | 495 days ago | IN | 0 ETH | 0.00000466 | ||||
| Claim Pack | 8850926 | 495 days ago | IN | 0 ETH | 0.00000083 | ||||
| Claim Pack | 8850912 | 495 days ago | IN | 0 ETH | 0.00000082 | ||||
| Claim Specific U... | 8850901 | 495 days ago | IN | 0 ETH | 0.00000438 | ||||
| Claim Specific U... | 8850888 | 495 days ago | IN | 0 ETH | 0.00000484 | ||||
| Claim Specific U... | 8850873 | 495 days ago | IN | 0 ETH | 0.00000474 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
BattlePass
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 { OwnableRoles } from "@solady/src/auth/OwnableRoles.sol";
import { ECDSA } from "@solady/src/utils/ECDSA.sol";
import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol";
import { AccessRoles } from "./access/AccessRoles.sol";
import { Game } from "./types/Game.sol";
import { IBattlePass } from "./interfaces/IBattlePass.sol";
import { IBlast } from "./interfaces/IBlast.sol";
import { IGlory } from "./interfaces/IGlory.sol";
import { ISeeder } from "./interfaces/ISeeder.sol";
import { IGameCards } from "./interfaces/IGameCards.sol";
import { IBaseCards } from "./interfaces/IBaseCards.sol";
import { IPackShop } from "./interfaces/IPackShop.sol";
/**
* @title BattlePass
* @notice This contract handles all functionality related to battle passes. Game Masters can add new battle passes
* and users can purchase and claim rewards when they have reached their battle pass has reached desired level.
*/
contract BattlePass is IBattlePass, OwnableRoles, Pausable {
using ECDSA for bytes32;
uint256 private constant _MAX_BPS = 10_000;
uint256[] private _unitRewards;
IBlast public immutable BLAST = IBlast(0x4300000000000000000000000000000000000002);
IGlory public immutable glory;
IGameCards public immutable gameCards;
IBaseCards public immutable baseCards;
IPackShop public packShop;
ISeeder public seeder;
uint256 public bpCount = 0;
address public signer;
address public treasury;
uint256 public burnFeeBps;
mapping(uint256 bpId => BattlePass bp) private _battlePasses;
mapping(address account => mapping(uint256 bpId => bool hasBp)) public hasBattlePass;
mapping(address account => mapping(uint256 bpId => mapping(uint256 rewardId => bool hasClaimed))) public
rewardClaimed;
constructor(
address _gameMaster,
address _signer,
address _treasury,
address _glory,
address _gameCards,
address _baseCards,
address _packShop,
address _seeder,
address _blastGovernor
) {
if (
_gameMaster == address(0) || _signer == address(0) || _treasury == address(0) || _glory == address(0)
|| _gameCards == address(0) || _baseCards == address(0) || _packShop == address(0) || _seeder == address(0)
|| _blastGovernor == address(0)
) revert ZeroAddress();
BLAST.configureClaimableGas();
BLAST.configureGovernor({ _governor: _blastGovernor });
_initializeOwner({ newOwner: msg.sender });
_grantRoles({ user: _gameMaster, roles: AccessRoles.GAME_MASTER_ROLE });
signer = _signer;
treasury = _treasury;
glory = IGlory(_glory);
gameCards = IGameCards(_gameCards);
baseCards = IBaseCards(_baseCards);
packShop = IPackShop(_packShop);
seeder = ISeeder(_seeder);
emit SignerUpdated({ oldSigner: address(0), newSigner: _signer });
emit TreasuryUpdated({ oldTreasury: address(0), newTreasury: _treasury });
}
/**
* @inheritdoc IBattlePass
*/
function buyBattlePass(uint256 bpId) external whenNotPaused {
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
if (hasBattlePass[msg.sender][bpId]) revert HasBattlePass();
BattlePass memory bp = _battlePasses[bpId];
if (!bp.purchasable) revert NotPurchasable();
uint256 burnAmount = bp.price * burnFeeBps / _MAX_BPS;
if (burnAmount != 0) {
glory.burnFrom({ account: msg.sender, value: burnAmount });
}
glory.transferFrom({ from: msg.sender, to: treasury, value: bp.price - burnAmount });
hasBattlePass[msg.sender][bpId] = true;
emit BattlePassPurchased({ account: msg.sender, battlePass: bp });
}
/**
* @inheritdoc IBattlePass
*/
function giftBattlePass(uint256 bpId, address receiver) external whenNotPaused {
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
if (receiver == address(0)) revert ZeroAddress();
if (hasBattlePass[receiver][bpId]) revert HasBattlePass();
BattlePass memory bp = _battlePasses[bpId];
if (!bp.purchasable) revert NotPurchasable();
uint256 burnAmount = bp.price * burnFeeBps / _MAX_BPS;
if (burnAmount != 0) {
glory.burnFrom({ account: msg.sender, value: burnAmount });
}
glory.transferFrom({ from: msg.sender, to: treasury, value: bp.price - burnAmount });
hasBattlePass[receiver][bpId] = true;
emit BattlePassPurchased({ account: receiver, battlePass: bp });
}
/**
* @inheritdoc IBattlePass
*/
function claimUnitCard(
uint256 bpId,
uint256 rewardId,
Game.CardTier cardTier,
bytes calldata signature
)
external
whenNotPaused
{
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
if (cardTier == Game.CardTier.UNDEFINED) revert InvalidCardTier();
bytes32 digest =
keccak256(abi.encodePacked(msg.sender, bpId, rewardId, cardTier, "CUC")).toEthSignedMessageHash();
if (digest.recover(signature) != signer) revert SignerMismatch();
if (rewardClaimed[msg.sender][bpId][rewardId]) revert HasClaimed();
rewardClaimed[msg.sender][bpId][rewardId] = true;
uint256[] memory baseIds = new uint256[](1);
uint256 ephemeralSeed = seeder.getAndUpdateGameSeed();
baseIds[0] = _unitRewards[ephemeralSeed % _unitRewards.length];
uint256[6] memory weights;
weights[uint256(cardTier) - 1] = 10_000;
gameCards.mintCards({ cardIds: baseIds, tierWeights: weights, receiver: msg.sender });
emit RewardClaimed({ account: msg.sender, rewardId: rewardId });
}
/**
* @inheritdoc IBattlePass
*/
function claimSpecificUnitCard(
uint256 bpId,
uint256 rewardId,
uint256 baseCardId,
Game.CardTier cardTier,
bytes calldata signature
)
external
whenNotPaused
{
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
if (cardTier == Game.CardTier.UNDEFINED) revert InvalidCardTier();
bytes32 digest = keccak256(abi.encodePacked(msg.sender, bpId, rewardId, baseCardId, cardTier, "CSUC"))
.toEthSignedMessageHash();
if (digest.recover(signature) != signer) revert SignerMismatch();
if (rewardClaimed[msg.sender][bpId][rewardId]) revert HasClaimed();
rewardClaimed[msg.sender][bpId][rewardId] = true;
uint256[] memory baseIds = new uint256[](1);
baseIds[0] = baseCardId;
uint256[6] memory weights;
weights[uint256(cardTier) - 1] = 10_000;
gameCards.mintCards({ cardIds: baseIds, tierWeights: weights, receiver: msg.sender });
emit RewardClaimed({ account: msg.sender, rewardId: rewardId });
}
/**
* @inheritdoc IBattlePass
*/
function claimArtifactCard(
uint256 bpId,
uint256 rewardId,
uint256 baseCardId,
bytes calldata signature
)
external
whenNotPaused
{
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
if (baseCards.baseCards(baseCardId).cardType != Game.CardType.ARTIFACT) revert InvalidBaseCardId();
// BPAC - Battle Pass Artifact Claim
bytes32 digest =
keccak256(abi.encodePacked(msg.sender, bpId, rewardId, baseCardId, "CAC")).toEthSignedMessageHash();
if (digest.recover(signature) != signer) revert SignerMismatch();
if (rewardClaimed[msg.sender][bpId][rewardId]) revert HasClaimed();
rewardClaimed[msg.sender][bpId][rewardId] = true;
uint256[] memory cardIds = new uint256[](1);
cardIds[0] = baseCardId;
// Weights do not need to be set as artifact tiers are set at the base card level.
uint256[6] memory weights;
gameCards.mintCards({ cardIds: cardIds, tierWeights: weights, receiver: msg.sender });
emit RewardClaimed({ account: msg.sender, rewardId: rewardId });
}
/**
* @inheritdoc IBattlePass
*/
function claimPack(
uint256 bpId,
uint256 rewardId,
uint256 packId,
uint256 amount,
bytes calldata signature
)
external
whenNotPaused
{
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
bytes32 digest =
keccak256(abi.encodePacked(msg.sender, bpId, rewardId, packId, amount, "CP")).toEthSignedMessageHash();
if (digest.recover(signature) != signer) revert SignerMismatch();
if (rewardClaimed[msg.sender][bpId][rewardId]) revert HasClaimed();
rewardClaimed[msg.sender][bpId][rewardId] = true;
/// @dev Since `addFreePackClaims` sets rather than increments, get the current number of claims the caller
/// has and increment the return value. This is to prevent the caller from losing packs.
uint256 currentClaims = packShop.freePackClaims({ account: msg.sender, packId: packId });
packShop.addFreePackClaims({ account: msg.sender, packId: packId, amount: currentClaims + amount });
emit RewardClaimed({ account: msg.sender, rewardId: rewardId });
}
/**
* @inheritdoc IBattlePass
*/
function claimGlory(
uint256 bpId,
uint256 rewardId,
uint256 amount,
bytes calldata signature
)
external
whenNotPaused
{
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
bytes32 digest = keccak256(abi.encodePacked(msg.sender, bpId, rewardId, amount, "CG")).toEthSignedMessageHash();
if (digest.recover(signature) != signer) revert SignerMismatch();
if (rewardClaimed[msg.sender][bpId][rewardId]) revert HasClaimed();
rewardClaimed[msg.sender][bpId][rewardId] = true;
glory.transfer({ to: msg.sender, value: amount });
emit RewardClaimed({ account: msg.sender, rewardId: rewardId });
}
/**
* @inheritdoc IBattlePass
*/
function addBattlePass(uint256 price, bool isPurchasable) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (price == 0) revert InvalidPrice();
/// @dev Pre-increment to use `0` as an invalid identifier.
uint256 bpId = ++bpCount;
BattlePass memory bp = BattlePass({ price: price, purchasable: isPurchasable });
_battlePasses[bpId] = bp;
emit BattlePassAdded({ bpId: bpId, battlePass: bp });
}
/**
* @inheritdoc IBattlePass
*/
function giveBattlePass(
uint256 bpId,
address[] calldata receivers
)
external
onlyRoles(AccessRoles.GAME_MASTER_ROLE)
{
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
if (receivers.length == 0) revert ZeroLengthArray();
BattlePass memory bp = _battlePasses[bpId];
for (uint256 i = 0; i < receivers.length; i++) {
address receiver = receivers[i];
hasBattlePass[receiver][bpId] = true;
emit BattlePassPurchased({ account: receiver, battlePass: bp });
}
}
/**
* Function used to toggle purchasability for a specific battle pass.
* @param bpId Unique season identifier.
*/
function togglePurchase(uint256 bpId) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (bpId == 0 || bpId > bpCount) revert InvalidBpId();
bool oldFlag = _battlePasses[bpId].purchasable;
_battlePasses[bpId].purchasable = !oldFlag;
emit BattlePassToggled({ flag: !oldFlag });
}
/**
* Function used to set possible unit and artifact reward cards.
* @param unitIds Array of base unit card identifiers.
*/
function setRewards(uint256[] calldata unitIds) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (unitIds.length == 0) revert ZeroLengthArray();
uint256 maxBaseId = baseCards.baseCardCount();
Game.BaseCard memory baseCard;
// Iterate over each provided unit ID ensuring validity and no duplicates.
uint256 dupes;
for (uint256 i = 0; i < unitIds.length; i++) {
uint256 baseUnitId = unitIds[i];
if (baseUnitId == 0 || baseUnitId > maxBaseId) revert InvalidBaseCardId();
if (dupes >> baseUnitId & 1 == 1) revert DuplicateBaseCardId();
baseCard = baseCards.baseCards({ baseCardId: baseUnitId });
if (baseCard.cardType != Game.CardType.UNIT) revert InvalidCardType();
dupes |= 1 << baseUnitId;
}
_unitRewards = unitIds;
emit RewardsUpdated(unitIds);
}
/**
* @inheritdoc IBattlePass
*/
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 IBattlePass
*/
function setTreasury(address newTreasury) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newTreasury == address(0)) revert ZeroAddress();
address oldTreasury = treasury;
treasury = newTreasury;
emit TreasuryUpdated(oldTreasury, newTreasury);
}
/**
* @inheritdoc IBattlePass
*/
function setBurnBps(uint256 newBurnBps) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newBurnBps > _MAX_BPS) revert InvalidBps();
uint256 oldBurnBps = burnFeeBps;
burnFeeBps = newBurnBps;
emit BurnBpsUpdated(oldBurnBps, newBurnBps);
}
/**
* @inheritdoc IBattlePass
*/
function withdrawGlory(address receiver, uint256 amount) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (receiver == address(0)) revert ZeroAddress();
glory.transfer({ to: receiver, value: amount });
}
/**
* @inheritdoc IBattlePass
*/
function pause() external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
_pause();
}
/**
* @inheritdoc IBattlePass
*/
function unpause() external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
_unpause();
}
/**
* @inheritdoc IBattlePass
*/
function battlePasses() external view returns (BattlePass[] memory) {
BattlePass[] memory bps = new BattlePass[](bpCount);
for (uint256 i = 0; i < bps.length; i++) {
bps[i] = _battlePasses[i + 1];
}
return bps;
}
/**
* @inheritdoc IBattlePass
*/
function battlePasses(uint256 bpId) external view returns (BattlePass memory) {
return _battlePasses[bpId];
}
/**
* @inheritdoc IBattlePass
*/
function hasCurrentBattlePass(address account) external view returns (bool) {
return hasBattlePass[account][bpCount];
}
/**
* @inheritdoc IBattlePass
*/
function currentBattlePass() external view returns (BattlePass memory) {
return _battlePasses[bpCount];
}
/**
* @inheritdoc IBattlePass
*/
function unitRewards() external view returns (uint256[] memory) {
uint256[] memory _units = new uint256[](_unitRewards.length);
for (uint256 i = 0; i < _units.length; i++) {
_units[i] = _unitRewards[i];
}
return _units;
}
}// 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) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// 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;
/**
* @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
pragma solidity 0.8.20;
import { Game } from "../types/Game.sol";
/**
* @title IBattlePass
* @notice Interface for BattlePass.
*/
interface IBattlePass {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided as input.
*/
error ZeroAddress();
/**
* Thrown when an invalid price is provided as input.
*/
error InvalidPrice();
/**
* Thrown when an invalid battle pass identifier is provided as input.
*/
error InvalidBpId();
/**
* Thrown when a zero length array is provided as input.
*/
error ZeroLengthArray();
/**
* Thrown when a caller already has a specific battle pass.
*/
error HasBattlePass();
/**
* Thrown when a battle pass is not available for purchase.
*/
error NotPurchasable();
/**
* Thrown when the recovered signer doesn't match the expected signer.
*/
error SignerMismatch();
/**
* Thrown when an invalid base card identifier is provided.
*/
error InvalidBaseCardId();
/**
* Thrown when an invalid basis points value is provided.
*/
error InvalidBps();
/**
* Thrown when an undefined card tier is provided.
*/
error InvalidCardTier();
/**
* Thrown when the caller has already claimed the reward.
*/
error HasClaimed();
/**
* Thrown when a nonce has been used previously.
*/
error NonceUsed();
/**
* Thrown when a base card identifier is provided twice.
*/
error DuplicateBaseCardId();
/**
* Thrown when an invalid reward card type is provided.
*/
error InvalidCardType();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
struct BattlePass {
uint256 price;
bool purchasable;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when a battle pass is added.
* @param bpId Unique battle pass identifier.
* @param battlePass `BattlePass` struct.
*/
event BattlePassAdded(uint256 indexed bpId, BattlePass battlePass);
/**
* Emitted when a battle pass is purchased.
* @param account Address of the account that purchased the Battle Pass.
* @param battlePass `BattlePass` struct.
*/
event BattlePassPurchased(address indexed account, BattlePass battlePass);
/**
* Emitted when a battle pass reward is claimed.
* @param account Address of the account that claimed the reward.
* @param rewardId Off-chain reward identifier.
*/
event RewardClaimed(address indexed account, uint256 rewardId);
/**
* Emitted when battle pass rewards are updated.
* @param unitIds Array of base unit card identifiers.
*/
event RewardsUpdated(uint256[] unitIds);
/**
* Emitted when the purchasability of a battle pass is toggled.
* @param flag Flag indicating if the battle pass is purchasable or not.
*/
event BattlePassToggled(bool flag);
/**
* 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);
/**
* Emmited when the treasury address is updated.
* @param oldTreasury Old treasury address.
* @param newTreasury New treasury address.
*/
event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);
/**
* Emitted when the burn basis points are updated.
* @param oldBurnBps Old burn basis points.
* @param newBurnBps New burn basis points.
*/
event BurnBpsUpdated(uint256 oldBurnBps, uint256 newBurnBps);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to purchase a battle pass.
* @param bpId Unique battle pass identifier.
*/
function buyBattlePass(uint256 bpId) external;
/**
* Function used to buy a battle pass for another user.
* @param bpId Unique battle pass identifier.
* @param receiver Receiving address of the battle pass.
*/
function giftBattlePass(uint256 bpId, address receiver) external;
/**
* Function used to claim a unit card as a battle pass reward.
* @param bpId Unique battle pass identifier.
* @param rewardId Off-chain reward identifier.
* @param cardTier Tier of card to claim.
* @param signature Signed message digest.
*/
function claimUnitCard(uint256 bpId, uint256 rewardId, Game.CardTier cardTier, bytes calldata signature) external;
/**
* Function used to claim a specific unit card as a battle pass reward.
* @param bpId Unique battle pass identifier.
* @param rewardId Off-chain reward identifier.
* @param baseCardId Unique base card identifier.
* @param cardTier Tier of card to claim.
* @param signature Signed message digest.
*/
function claimSpecificUnitCard(
uint256 bpId,
uint256 rewardId,
uint256 baseCardId,
Game.CardTier cardTier,
bytes calldata signature
)
external;
/**
* Function used to claim an artifact card as a battle pass reward.
* @param bpId Unique battle pass identifier.
* @param rewardId Off-chain reward identifier.
* @param baseCardId Base card identifier.
* @param signature Signed message digest.
*/
function claimArtifactCard(uint256 bpId, uint256 rewardId, uint256 baseCardId, bytes calldata signature) external;
/**
* Function used to claim a booster pack as a battle pass reward.
* @param bpId Unique battle pass identifier.
* @param rewardId Off-chain reward identifier.
* @param packId `PackShop` pack identifier.
* @param amount Number of packs to claim.
* @param signature Signed message digest.
*/
function claimPack(
uint256 bpId,
uint256 rewardId,
uint256 packId,
uint256 amount,
bytes calldata signature
)
external;
/**
* Function used to claim GLORY as a battle pass reward.
* @param bpId Unique battle pass identifier.
* @param rewardId Off-chain reward identifier.
* @param amount Amount of GLORY to claim.
* @param signature Signed message digest.
*/
function claimGlory(uint256 bpId, uint256 rewardId, uint256 amount, bytes calldata signature) external;
/**
* Function used to add a new battle pass.
* @param price Cost of the battle pass in GLORY token.
* @param isPurchasable Flag indicating if the newly created battle pass will be purchasable after creation.
*/
function addBattlePass(uint256 price, bool isPurchasable) external;
/**
* Function used to gift battle passes to a list of receivers.
* @param bpId Unique battle pass identifier.
* @param receivers Array of receiver addresses.
*/
function giveBattlePass(uint256 bpId, address[] calldata receivers) external;
/**
* Function used to set a new `signer` address.
* @param newSigner New `signer` address value.
*/
function setSigner(address newSigner) external;
/**
* Function used to update the treasury address.
* @param newTreasury Newly desired treasury address.
*/
function setTreasury(address newTreasury) external;
/**
* Function used to set a new burn basis points value.
* @param newBurnBps New burn basis points.
*/
function setBurnBps(uint256 newBurnBps) external;
/**
* Function used to withdraw GLORY.
* @param amount Amount of GLORY to withdraw.
*/
function withdrawGlory(address receiver, uint256 amount) external;
/**
* Function used to pause the contract.
*/
function pause() external;
/**
* Function used to unpause the contract.
*/
function unpause() external;
/**
* Function used to view all battle passes that have been created.
*/
function battlePasses() external view returns (BattlePass[] memory);
/**
* Function used to view information relating to a single battle pass.
* @param bpId Unique battle pass identifier.
*/
function battlePasses(uint256 bpId) external view returns (BattlePass memory);
/**
* Function used to view all possible unit rewards.
*/
function unitRewards() external view returns (uint256[] memory);
/**
* Function that returns whether a user has the current season battle pass.
* @param account Desired address to lookup.
*/
function hasCurrentBattlePass(address account) external view returns (bool);
/**
* Function used to view the current battle pass.
*/
function currentBattlePass() external view returns (BattlePass memory);
}// 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;
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
/**
* @title IGlory
* @notice Interface for Glory.
*/
interface IGlory is IERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided as input.
*/
error ZeroAddress();
/**
* Thrown when trying to enable transfers when transfers are already enabled.
*/
error TradingEnabled();
/**
* Thrown when the caller is not authorized to transfer tokens.
*/
error CallerBlocked();
/**
* Thrown when a user exceeds the maximum wallet balance of tokens.
*/
error OverMaxBalance();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to destroy `value` amount of tokens from the caller.
* @param value Amount of tokens to destroy.
*
* See {ERC20-_burn}.
*/
function burn(uint256 value) external;
/**
* Function used to destroy `value` amount of tokens from `account`, deducting from
* the caller's allowance.
*
* @param account Address to destroy tokens from.
* @param value Amount of tokens to destroy.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for `accounts`'s tokens of at least
* `value`.
*/
function burnFrom(address account, uint256 value) external;
/**
* Function used to update the mapping of addresses that can transfer tokens when transfers are disabled.
* @param account Address to modify whitelisting for.
* @param status Flag indicating if `account` can transfer tokens or not.
*/
function updateWhitelist(address account, bool status) external;
/**
* Function used to enable token transfers.
*/
function enableTransfers() external;
/**
* Function used to set a new `maxBalance` value.
* @param amount New maximum amount of tokens a user can hold.
*/
function setMaxBalance(uint256 amount) external;
/**
* Function used to toggle the check for maxiumum wallet balances.
*/
function toggleMaxBalanceCheck() external;
/**
* Function used to view if an account is whitelisted.
*/
function whitelist(address account) external view returns (bool);
/**
* Function used to set the pair address.
*/
function setPair(address pairAddr) external;
/**
* Function used to view if transfers are currently disabled.
*/
function transfersDisabled() external view returns (bool);
/**
* Function used to view if the maximum wallet limit is being enforced.
*/
function enforceMaxBalance() external view returns (bool);
/**
* Function used to view the maximum number of tokens a wallet can hold, assuming not transferred
* from a whitelisted address.
*/
function maxBalance() external view returns (uint256);
/**
* Function used to view the Thruster pair.
*/
function pair() external view returns (address);
}// 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 { 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 IPackShop
* @notice Interface for PackShop.
*/
interface IPackShop {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided as an input value.
*/
error ZeroAddress();
/**
* Thrown when two input arrays differ in length.
*/
error ArrayLengthMismatch();
/**
* Thrown when an input array has zero length.
*/
error ZeroLengthArray();
/**
* Thrown when the card ID provided does not exist.
*/
error NonExistentCardId();
/**
* Thrown when a pack has an invalid pull amount.
*/
error InvalidPullAmount();
/**
* Thrown when `Pack.endTime` is less than or equal to `Pack.startTime`.
*/
error InvalidSaleWindow();
/**
* Thrown when an invalid `Pack.supply` value is provided.
*/
error InvalidPackSupply();
/**
* Thrown when an invalid `Pack.limit` value is provided.
*/
error InvalidPurchaseLimit();
/**
* Thrown when the sum of Pack.cardWeights doesn't equal 10_000.
*/
error InvalidCardWeightSum();
/**
* Thrown when the sum of Pack.tierWeights doesn't equal 10_000.
*/
error InvalidTierWeightSum();
/**
* Thrown when the pack ID provided doesn't exist.
*/
error NonExistentPackId();
/**
* Thrown when either `Pack.startTime` has not been reached yet or `Pack.endTime` has already passed.
*/
error SaleNotActive();
/**
* Thrown when a pack has sold out.
*/
error PackSoldOut();
/**
* Thrown when a user attempts to claim a pack without a free claim.
*/
error NoFreeClaims();
/**
* Thrown when an account trys to purchase over the `Pack.purchaseLimit` amount.
*/
error OverPurchaseLimit();
/**
* Thrown when trying to set the `Shop.burnBps` above the maximum value.
*/
error OverMaxBps();
/**
* Thrown when trying to release a pack with an invalid end time.
*/
error InvalidEndTime();
/**
* Thrown when the recovered signer doesn't match the set signer.
*/
error SignerMismatch();
/**
* Thrown when a nonce has been used previously.
*/
error NonceUsed();
/**
* Thrown when the caller is not the origin.
*/
error CallerNotOrigin();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Struct encapsulating information related to a pack.
* @param price Price in token of a pack.
* @param pulls Number of cards that are given when opening this pack.
* @param startTime Timestamp indicating when the pack becomes purchasable.
* @param endTime Timestamp indicating when the pack can no longer be purchased.
* @param supply Number of times this pack can be purchased.
* @param purchaseLimit Number of times this pack can be purchased by a single account.
* @param signerGated Flag if the pack requires a signature to mint.
* @param cardIds Array of possible card IDs that can be obtained from this pack.
* @param cardWeights Array of card weights that determine the probability of rolling each card.
* @param tierWeights Array of card tier weights that determine the probability of rolling a certain tier of card.
*/
struct Pack {
uint256 price;
uint256 pulls;
uint256 startTime;
uint256 endTime;
uint256 supply;
uint256 purchaseLimit;
bool signerGated;
uint256[] cardIds;
uint256[] cardWeights;
uint256[6] tierWeights;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when a new pack is added to the shop.
* @param packId Unique pack identifier.
* @param newPack New Pack information.
*/
event PackAdded(uint256 indexed packId, Pack newPack);
/**
* Emitted when an existing pack is updated.
* @param packId Unique pack identifier.
* @param oldPack Old Pack information.
* @param newPack New Pack information.
*/
event PackUpdated(uint256 indexed packId, Pack oldPack, Pack newPack);
/**
* Emitted when a pack sale window is updated.
* @param packId Unique pack identifier.
* @param startTime Start timestamp of the sale window.
* @param endTime End timestamp fo the sale window.
*/
event SaleWindowUpdated(uint256 indexed packId, uint256 startTime, uint256 endTime);
/**
* Emitted when a new pack is purchased.
* @param account Account that purchased the pack.
* @param packId Unique pack identifier.
*/
event PackPurchased(address indexed account, uint256 indexed packId);
/**
* Emitted when a pack is redeemed with a code.
* @param account Account that redeemed the pack.
* @param packId Unique pack identifier.
* @param code Code used during redemption.
*/
event PackRedeemed(address indexed account, uint256 indexed packId, string code);
/**
* Emitted when a pack is restocked.
* @param packId Unique pack idenitifier.
* @param amount New pack supply.
*/
event PackSupplyUpdated(uint256 indexed packId, uint256 amount);
/**
* Emitted when a pack is sunset.
* @param packId Unique pack identifier.
*/
event PackSunset(uint256 indexed packId);
/**
* Emitted when a pack is rereleased.
* @param packId Unique pack identifier.
* @param endTime Timestamp that the pack no longer becomes purchasable.
*/
event PackRereleased(uint256 indexed packId, uint256 endTime);
/**
* Emitted when a pack is claimed.
* @param account Account that claimed the pack.
* @param packId Unique pack identifier.
*/
event PackClaimed(address indexed account, uint256 indexed packId);
/**
* Emitted when an address has been allocated free packs to claim.
* @param account Address that has been given free packs.
* @param packId Unique pack identifier.
* @param amount Number of free packs to allocate.
*/
event PackClaimsAdded(address indexed account, uint256 indexed packId, uint256 amount);
/**
* Emmited when the treasury address is updated.
* @param oldTreasury Old treasury address.
* @param newTreasury New treasury address.
*/
event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);
/**
* Emitted when the burn basis points amount is updated.
* @param oldBurnBps Old burn basis points amount.
* @param newBurnBps New burn basis points amount.
*/
event BurnBpsUpdated(uint256 oldBurnBps, uint256 newBurnBps);
/**
* 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 the `gameCards` address is updated.
* @param oldGameCards Old `gameCards` address.
* @param newGameCards New `gameCards` address.
*/
event GameCardsUpdated(address oldGameCards, address newGameCards);
/**
* Emitted when the `seeder` address is updated.
* @param oldSeeder Old `seeder` address.
* @param newSeeder New `seeder` address.
*/
event SeederUpdated(address oldSeeder, address newSeeder);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to initialize the PackShop contract.
* @param _owner Contract owner.
* @param _gameMaster Designed Game Master.
* @param _seeder Seeder contract.
* @param _gameCards GameCards contract.
* @param _baseCards BaseCards contract.
* @param _token Glory token contract.
* @param _treasury Treasury address.
* @param _signer Signer address.
* @param _blastGovernor Blast Governor contract address.c
* @param _burnBps Burn basis points to use on deployment.
*/
function initialize(
address _owner,
address _gameMaster,
address _seeder,
address _gameCards,
address _baseCards,
address _token,
address _treasury,
address _signer,
address _blastGovernor,
uint256 _burnBps
)
external;
/**
* Function to purchase a pack.
* @param packId Unique pack identifier.
* @param signature Signed message digest.
*/
function buyPack(uint256 packId, bytes calldata signature) external;
/**
* Function used to claim a pack for free.
* @param packId Unique pack identifier.
*/
function claimPack(uint256 packId) external;
/**
* Function used to add a new card pack.
* @param newPack Newly desired Pack information.
*/
function addPack(Pack calldata newPack) external;
/**
* Function used to add free pack claims for an address, free packs do not have any impact on the pack supply
* or the pack purchase limit.
* @param account Address to add free pack claims.
* @param packId Unique pack identifier.
* @param amount Number of free packs to allocate.
*/
function addFreePackClaims(address account, uint256 packId, uint256 amount) external;
/**
* Function used to modify an existing card pack.
* @param packId Unique pack identifier.
* @param newPack Newly desired Pack information.
*/
function updatePack(uint256 packId, Pack calldata newPack) external;
/**
* Function used to update the sale window of a pack.
* @param packId Unique pack identifier.
* @param startTime Start timestamp of the sale window.
* @param endTime End timestamp fo the sale window.
*/
function setPackSaleWindow(uint256 packId, uint256 startTime, uint256 endTime) external;
/**
* Function used to set the supply of a pack.
* @param packId Unique pack identifier.
* @param amount New pack supply.
*/
function setPackSupply(uint256 packId, uint256 amount) external;
/**
* Function used to sunset a pack, making it unpurchasable.
* @param packId Unique pack identifier.
*/
function sunsetPack(uint256 packId) external;
/**
* Function used to immediately re-release a pre-existing pack.
* @param packId Unique pack identifier.
* @param endTime Timestamp the pack sale sends.
*/
function rereleasePack(uint256 packId, uint256 endTime) external;
/**
* Function used to redeem a pack using a code.
* @param packId Unique pack identifier.
* @param nonce One time use identifier.
* @param code Pack redemption code.
* @param signature Signed message digest.
*/
function redeemPack(uint256 packId, uint256 nonce, string calldata code, bytes calldata signature) external;
/**
* Function used to update the treasury address.
* @param newTreasury Newly desired treasury address.
*/
function setTreasury(address newTreasury) external;
/**
* Function used to update the signer address.
* @param newSigner Newly desired signer address
*/
function setSigner(address newSigner) external;
/**
* Function used to update the burn basis points used for token burn calculations.
* @param newBurnBps Newly desired burn basis points amount.
*/
function setBurnBps(uint256 newBurnBps) external;
/**
* Function used to set a new `baseCards` address value.
* @param newBaseCards New `baseCards` address.
*/
function setBaseCards(address newBaseCards) external;
/**
* Function used to set a new `gameCards` address value.
* @param newGameCards New `gameCards` address.
*/
function setGameCards(address newGameCards) external;
/**
* Function used to set a new `seeder` address value.
* @param newSeeder New `seeder` address.
*/
function setSeeder(address newSeeder) external;
/**
* Function used to view the ID of the next added pack.
*/
function nextPackId() external view returns (uint256);
/**
* Function used to view the current burn basis points.
*/
function burnBps() external view returns (uint256);
/**
* Function used to view the current treasury address.
*/
function treasury() external view returns (address);
/**
* Function used to view the current signer address.
*/
function signer() external view returns (address);
/**
* Function used to view the data associated with a given pack identifier.
* @param packId Unique pack identifier.
*/
function packs(uint256 packId) external view returns (Pack memory);
/**
* Function used to view the amount of a specific pack an account has purchased.
* @param account Address to lookup.
* @param packId Unique pack identifier.
*/
function packsPurchased(address account, uint256 packId) external view returns (uint256);
/**
* Function used to view the amount of free pack claims an account has.
* @param account Address to lookup.
* @param packId Unique pack identifier.
*/
function freePackClaims(address account, uint256 packId) external view returns (uint256);
}// 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) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721AUpgradeable.sol';
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// 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);
}{
"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":[{"internalType":"address","name":"_gameMaster","type":"address"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_glory","type":"address"},{"internalType":"address","name":"_gameCards","type":"address"},{"internalType":"address","name":"_baseCards","type":"address"},{"internalType":"address","name":"_packShop","type":"address"},{"internalType":"address","name":"_seeder","type":"address"},{"internalType":"address","name":"_blastGovernor","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"DuplicateBaseCardId","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"HasBattlePass","type":"error"},{"inputs":[],"name":"HasClaimed","type":"error"},{"inputs":[],"name":"InvalidBaseCardId","type":"error"},{"inputs":[],"name":"InvalidBpId","type":"error"},{"inputs":[],"name":"InvalidBps","type":"error"},{"inputs":[],"name":"InvalidCardTier","type":"error"},{"inputs":[],"name":"InvalidCardType","type":"error"},{"inputs":[],"name":"InvalidPrice","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NonceUsed","type":"error"},{"inputs":[],"name":"NotPurchasable","type":"error"},{"inputs":[],"name":"SignerMismatch","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroLengthArray","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"bpId","type":"uint256"},{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"purchasable","type":"bool"}],"indexed":false,"internalType":"struct IBattlePass.BattlePass","name":"battlePass","type":"tuple"}],"name":"BattlePassAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"purchasable","type":"bool"}],"indexed":false,"internalType":"struct IBattlePass.BattlePass","name":"battlePass","type":"tuple"}],"name":"BattlePassPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"flag","type":"bool"}],"name":"BattlePassToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBurnBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBurnBps","type":"uint256"}],"name":"BurnBpsUpdated","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardId","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"unitIds","type":"uint256[]"}],"name":"RewardsUpdated","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":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":"address","name":"oldTreasury","type":"address"},{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BLAST","outputs":[{"internalType":"contract IBlast","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isPurchasable","type":"bool"}],"name":"addBattlePass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseCards","outputs":[{"internalType":"contract IBaseCards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"}],"name":"battlePasses","outputs":[{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"purchasable","type":"bool"}],"internalType":"struct IBattlePass.BattlePass","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"battlePasses","outputs":[{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"purchasable","type":"bool"}],"internalType":"struct IBattlePass.BattlePass[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bpCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"}],"name":"buyBattlePass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"uint256","name":"rewardId","type":"uint256"},{"internalType":"uint256","name":"baseCardId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimArtifactCard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"uint256","name":"rewardId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimGlory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"uint256","name":"rewardId","type":"uint256"},{"internalType":"uint256","name":"packId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimPack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"uint256","name":"rewardId","type":"uint256"},{"internalType":"uint256","name":"baseCardId","type":"uint256"},{"internalType":"enum Game.CardTier","name":"cardTier","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimSpecificUnitCard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"uint256","name":"rewardId","type":"uint256"},{"internalType":"enum Game.CardTier","name":"cardTier","type":"uint8"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimUnitCard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentBattlePass","outputs":[{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"purchasable","type":"bool"}],"internalType":"struct IBattlePass.BattlePass","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameCards","outputs":[{"internalType":"contract IGameCards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"giftBattlePass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"address[]","name":"receivers","type":"address[]"}],"name":"giveBattlePass","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"glory","outputs":[{"internalType":"contract IGlory","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":"address","name":"account","type":"address"},{"internalType":"uint256","name":"bpId","type":"uint256"}],"name":"hasBattlePass","outputs":[{"internalType":"bool","name":"hasBp","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"hasCurrentBattlePass","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","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":[],"name":"packShop","outputs":[{"internalType":"contract IPackShop","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"account","type":"address"},{"internalType":"uint256","name":"bpId","type":"uint256"},{"internalType":"uint256","name":"rewardId","type":"uint256"}],"name":"rewardClaimed","outputs":[{"internalType":"bool","name":"hasClaimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seeder","outputs":[{"internalType":"contract ISeeder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newBurnBps","type":"uint256"}],"name":"setBurnBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"unitIds","type":"uint256[]"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSigner","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bpId","type":"uint256"}],"name":"togglePurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unitRewards","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawGlory","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
61010060405273430000000000000000000000000000000000000260805260006004553480156200002f57600080fd5b50604051620044c3380380620044c3833981016040819052620000529162000383565b6000805460ff191690556001600160a01b03891615806200007a57506001600160a01b038816155b806200008d57506001600160a01b038716155b80620000a057506001600160a01b038616155b80620000b357506001600160a01b038516155b80620000c657506001600160a01b038416155b80620000d957506001600160a01b038316155b80620000ec57506001600160a01b038216155b80620000ff57506001600160a01b038116155b156200011e5760405163d92e233d60e01b815260040160405180910390fd5b6080516001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200015c57600080fd5b505af115801562000171573d6000803e3d6000fd5b5050608051604051631d70c8d360e31b81526001600160a01b038581166004830152909116925063eb8646989150602401600060405180830381600087803b158015620001bd57600080fd5b505af1158015620001d2573d6000803e3d6000fd5b50505050620001e733620002be60201b60201c565b620001f4896001620002fa565b600580546001600160a01b03808b166001600160a01b03199283168117909355600680548b831690841617905588811660a05287811660c05286811660e0526002805487831690841617905560038054918616919092161790556040516000907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb908290a36040516001600160a01b038816906000907f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a908290a35050505050505050506200043e565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b62000308828260016200030c565b5050565b638b78c6d8600c52826000526020600c208054838117836200032f575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b80516001600160a01b03811681146200037e57600080fd5b919050565b60008060008060008060008060006101208a8c031215620003a357600080fd5b620003ae8a62000366565b9850620003be60208b0162000366565b9750620003ce60408b0162000366565b9650620003de60608b0162000366565b9550620003ee60808b0162000366565b9450620003fe60a08b0162000366565b93506200040e60c08b0162000366565b92506200041e60e08b0162000366565b91506200042f6101008b0162000366565b90509295985092959850929598565b60805160a05160c05160e051613ff7620004cc6000396000818161073101528181610b5d01528181610cd10152612a0d015260008181610909015281816111c5015281816127b10152612d4a0152600081816109ff015281816116c90152818161175701528181611be301528181612231015281816122bf015261291c015260006108490152613ff76000f3fe6080604052600436106103135760003560e01c8063715018a61161019a578063addc831e116100e1578063eb6be5be1161008a578063f188e7f611610064578063f188e7f6146109ed578063f2fde38b14610a21578063fee81cf414610a3457600080fd5b8063eb6be5be1461099a578063f04e283e146109ba578063f0f44260146109cd57600080fd5b8063bad956a0116100bb578063bad956a0146108f7578063c353d89f1461092b578063e99dcb881461094d57600080fd5b8063addc831e14610897578063b099ae1e146108b7578063b52f106f146108d757600080fd5b80638614c08a1161014357806397d757761161011d57806397d7577614610837578063a51898101461086b578063ac3692021461088157600080fd5b80638614c08a146107c35780638da5cb5b146107e35780638dedf7271461081757600080fd5b80637f874928116101745780637f874928146107535780638303cdd0146107735780638456cb59146107ae57600080fd5b8063715018a6146106f7578063793eac56146106ff5780637afb9b1d1461071f57600080fd5b80632de948071161025e57806354d1f13d1161020757806361d027b3116101e157806361d027b31461067d578063684931ed146106aa5780636c19e783146106d757600080fd5b806354d1f13d1461063d578063560e8ad9146106455780635c975abb1461066557600080fd5b806348c622d91161023857806348c622d9146105d35780634a4ee7b1146105f3578063514e62fc1461060657600080fd5b80632de948071461055d57806335dfa2361461059e5780633f4ba83a146105be57600080fd5b80631b65c949116102c0578063238ac9331161029a578063238ac9331461050857806325692962146105355780632954eb9e1461053d57600080fd5b80631b65c949146104835780631c10893f146104d55780631cd64df4146104e857600080fd5b80631284bc0a116102f15780631284bc0a1461040d57806313d886601461044e578063183a4f6e1461047057600080fd5b806302678ad614610318578063063395b0146103805780630eeb607f146103a2575b600080fd5b34801561032457600080fd5b5061036b61033336600461349b565b73ffffffffffffffffffffffffffffffffffffffff166000908152600960209081526040808320600454845290915290205460ff1690565b60405190151581526020015b60405180910390f35b34801561038c57600080fd5b50610395610a67565b60405161037791906134f8565b3480156103ae57600080fd5b506104006103bd36600461350b565b6040805180820190915260008082526020820152506000908152600860209081526040918290208251808401909352805483526001015460ff1615159082015290565b6040516103779190613524565b34801561041957600080fd5b5061036b61042836600461353d565b600a60209081526000938452604080852082529284528284209052825290205460ff1681565b34801561045a57600080fd5b5061046e6104693660046135bc565b610b13565b005b61046e61047e36600461350b565b610e2e565b34801561048f57600080fd5b506002546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610377565b61046e6104e33660046135fe565b610e3b565b3480156104f457600080fd5b5061036b6105033660046135fe565b610e51565b34801561051457600080fd5b506005546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b61046e610e70565b34801561054957600080fd5b5061046e610558366004613677565b610ec0565b34801561056957600080fd5b5061059061057836600461349b565b638b78c6d8600c908152600091909152602090205490565b604051908152602001610377565b3480156105aa57600080fd5b5061046e6105b93660046136ea565b611270565b3480156105ca57600080fd5b5061046e61140b565b3480156105df57600080fd5b5061046e6105ee366004613744565b61141e565b61046e6106013660046135fe565b611518565b34801561061257600080fd5b5061036b6106213660046135fe565b638b78c6d8600c90815260009290925260209091205416151590565b61046e61152a565b34801561065157600080fd5b5061046e61066036600461350b565b611566565b34801561067157600080fd5b5060005460ff1661036b565b34801561068957600080fd5b506006546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156106b657600080fd5b506003546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156106e357600080fd5b5061046e6106f236600461349b565b6118af565b61046e61197f565b34801561070b57600080fd5b5061046e61071a366004613774565b611993565b34801561072b57600080fd5b506104b07f000000000000000000000000000000000000000000000000000000000000000081565b34801561075f57600080fd5b5061046e61076e3660046137d5565b611ca3565b34801561077f57600080fd5b5061036b61078e3660046135fe565b600960209081526000928352604080842090915290825290205460ff1681565b3480156107ba57600080fd5b5061046e612058565b3480156107cf57600080fd5b5061046e6107de366004613821565b61206b565b3480156107ef57600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546104b0565b34801561082357600080fd5b5061046e61083236600461384d565b61242e565b34801561084357600080fd5b506104b07f000000000000000000000000000000000000000000000000000000000000000081565b34801561087757600080fd5b5061059060075481565b34801561088d57600080fd5b5061059060045481565b3480156108a357600080fd5b5061046e6108b236600461350b565b6127ea565b3480156108c357600080fd5b5061046e6108d23660046135fe565b612878565b3480156108e357600080fd5b5061046e6108f2366004613774565b61298f565b34801561090357600080fd5b506104b07f000000000000000000000000000000000000000000000000000000000000000081565b34801561093757600080fd5b50610940612d83565b604051610377919061389a565b34801561095957600080fd5b50604080518082018252600080825260209182018190526004548152600882528290208251808401909352805483526001015460ff16151590820152610400565b3480156109a657600080fd5b5061046e6109b536600461350b565b612e66565b61046e6109c836600461349b565b612f2a565b3480156109d957600080fd5b5061046e6109e836600461349b565b612f67565b3480156109f957600080fd5b506104b07f000000000000000000000000000000000000000000000000000000000000000081565b61046e610a2f36600461349b565b613037565b348015610a4057600080fd5b50610590610a4f36600461349b565b63389a75e1600c908152600091909152602090205490565b60015460609060009067ffffffffffffffff811115610a8857610a886138f3565b604051908082528060200260200182016040528015610ab1578160200160208202803683370190505b50905060005b8151811015610b0d5760018181548110610ad357610ad3613922565b9060005260206000200154828281518110610af057610af0613922565b602090810291909101015280610b0581613980565b915050610ab7565b50919050565b6001610b1e8161305e565b6000829003610b59576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c3702fa76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bea91906139b8565b9050610bf461338c565b6000805b85811015610ddf576000878783818110610c1457610c14613922565b9050602002013590508060001480610c2b57508481115b15610c62576040517fadb070da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8083901c600116600103610ca2576040517f2ba6e3e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fabb05174000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063abb0517490602401600060405180830381865afa158015610d2d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610d739190810190613c05565b9350600184604001516002811115610d8d57610d8d613d01565b14610dc4576040517f7dbbb63500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001901b919091179080610dd781613980565b915050610bf8565b50610dec600187876133f4565b507fc8b9ea2d5ab30c96c1b241d2e00783f61a129991e28be275597f70900182c2de8686604051610e1e929190613d30565b60405180910390a1505050505050565b610e383382613084565b50565b610e43613090565b610e4d82826130c6565b5050565b638b78c6d8600c90815260008390526020902054811681145b92915050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610ec86130d2565b851580610ed6575060045486115b15610f0d576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000836006811115610f2157610f21613d01565b03610f58576040517faae1f34100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610fb73388888888604051602001610f76959493929190613dc0565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691611016918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614611063576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208a8452825280832089845290915290205460ff16156110c0576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208a84528252808320898452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155815181815280830190925290918281019080368337019050509050858160008151811061113d5761113d613922565b60200260200101818152505061115161343f565b61271081600188600681111561116957611169613d01565b6111739190613e39565b6006811061118357611183613922565b60200201526040517f03728ca300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906303728ca3906111fe90859085903390600401613e4c565b600060405180830381600087803b15801561121857600080fd5b505af115801561122c573d6000803e3d6000fd5b50506040518a81523392507f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241915060200160405180910390a2505050505050505050565b600161127b8161305e565b831580611289575060045484115b156112c0576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008290036112fb576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526008602090815260408083208151808301909252805482526001015460ff16151591810191909152905b8381101561140357600085858381811061134657611346613922565b905060200201602081019061135b919061349b565b73ffffffffffffffffffffffffffffffffffffffff811660008181526009602090815260408083208c84529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551919250907f940206c6f5a27418505bf4749a3c0a97239e332c74cae71b8d2f471f2cb6f367906113e8908690613524565b60405180910390a250806113fb81613980565b91505061132a565b505050505050565b60016114168161305e565b610e386131b9565b60016114298161305e565b82600003611462576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060046000815461147390613980565b9182905550604080518082018252868152851515602080830191825260008581526008909152839020825181559051600190910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905590519192509082907f63d85844f48ee89556393c62467a122813caa566395ddbfd64f441bfaae926f190611509908490613524565b60405180910390a25050505050565b611520613090565b610e4d8282613084565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b61156e6130d2565b80158061157c575060045481115b156115b3576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260096020908152604080832084845290915290205460ff1615611608576040517fb8182bab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600860209081526040918290208251808401909352805483526001015460ff16151590820181905261166b576040517f9c45da5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061271060075483600001516116829190613eb1565b61168c9190613ef7565b9050801561173b576040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906379cc679090604401600060405180830381600087803b15801561172257600080fd5b505af1158015611736573d6000803e3d6000fd5b505050505b600654825173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116926323b872dd9233929190911690611791908690613e39565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064016020604051808303816000875af115801561180a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182e9190613f0b565b503360008181526009602090815260408083208784529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f940206c6f5a27418505bf4749a3c0a97239e332c74cae71b8d2f471f2cb6f367906118a2908590613524565b60405180910390a2505050565b60016118ba8161305e565b73ffffffffffffffffffffffffffffffffffffffff8216611907576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb90600090a3505050565b611987613090565b6119916000613236565b565b61199b6130d2565b8415806119a9575060045485115b156119e0576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810186905260548101859052607481018490527f43470000000000000000000000000000000000000000000000000000000000006094820152600090611a5890609601610f76565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691611ab7918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614611b04576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a60209081526040808320898452825280832088845290915290205460ff1615611b61576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600a602090815260408083208a845282528083208984529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810191909152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c659190613f0b565b5060405185815233907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f72419060200160405180910390a2505050505050565b611cab6130d2565b851580611cb9575060045486115b15611cf0576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481018790526054810186905260748101859052609481018490527f435000000000000000000000000000000000000000000000000000000000000060b4820152600090611d6f9060b601610f76565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691611dce918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614611e1b576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208a8452825280832089845290915290205460ff1615611e78576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600a602090815260408083208b845282528083208a845290915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560025490517f7094cc22000000000000000000000000000000000000000000000000000000008152600481019390935260248301889052909173ffffffffffffffffffffffffffffffffffffffff90911690637094cc2290604401602060405180830381865afa158015611f3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6091906139b8565b60025490915073ffffffffffffffffffffffffffffffffffffffff166335aa2c8c3388611f8d8986613f28565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff9093166004840152602483019190915260448201526064015b600060405180830381600087803b15801561200157600080fd5b505af1158015612015573d6000803e3d6000fd5b50506040518981523392507f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241915060200160405180910390a25050505050505050565b60016120638161305e565b610e3861329c565b6120736130d2565b811580612081575060045482115b156120b8576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612105576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116600090815260096020908152604080832085845290915290205460ff1615612170576040517fb8182bab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600860209081526040918290208251808401909352805483526001015460ff1615159082018190526121d3576040517f9c45da5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061271060075483600001516121ea9190613eb1565b6121f49190613ef7565b905080156122a3576040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906379cc679090604401600060405180830381600087803b15801561228a57600080fd5b505af115801561229e573d6000803e3d6000fd5b505050505b600654825173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116926323b872dd92339291909116906122f9908690613e39565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123969190613f0b565b5073ffffffffffffffffffffffffffffffffffffffff831660008181526009602090815260408083208884529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f940206c6f5a27418505bf4749a3c0a97239e332c74cae71b8d2f471f2cb6f36790612420908590613524565b60405180910390a250505050565b6124366130d2565b841580612444575060045485115b1561247b576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083600681111561248f5761248f613d01565b036124c6576040517faae1f34100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006124e233878787604051602001610f769493929190613f3b565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691612541918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff161461258e576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a60209081526040808320898452825280832088845290915290205460ff16156125eb576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208984528252808320888452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558151818152808301909252909182810190803683370190505090506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663055877756040518163ffffffff1660e01b81526004016020604051808303816000875af11580156126c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126e991906139b8565b60018054919250906126fb9083613fad565b8154811061270b5761270b613922565b90600052602060002001548260008151811061272957612729613922565b60200260200101818152505061273d61343f565b61271081600189600681111561275557612755613d01565b61275f9190613e39565b6006811061276f5761276f613922565b60200201526040517f03728ca300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906303728ca3906111fe90869085903390600401613e4c565b60016127f58161305e565b612710821115612831576040517fc6cc5d7f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780549083905560408051828152602081018590527f5fd4dd55bd00e4ef8693a73e37974145a97ddf1063426ef2b6d5afcc2d4a949791015b60405180910390a1505050565b60016128838161305e565b73ffffffffffffffffffffffffffffffffffffffff83166128d0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612965573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129899190613f0b565b50505050565b6129976130d2565b8415806129a5575060045485115b156129dc576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026040517fabb05174000000000000000000000000000000000000000000000000000000008152600481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063abb0517490602401600060405180830381865afa158015612a69573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612aaf9190810190613c05565b604001516002811115612ac457612ac4613d01565b14612afb576040517fadb070da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810186905260548101859052607481018490527f43414300000000000000000000000000000000000000000000000000000000006094820152600090612b7390609701610f76565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691612bd2918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614612c1f576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a60209081526040808320898452825280832088845290915290205460ff1615612c7c576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208984528252808320888452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558151818152808301909252909182810190803683370190505090508481600081518110612cf957612cf9613922565b602002602001018181525050612d0d61343f565b6040517f03728ca300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906303728ca390611fe790859085903390600401613e4c565b6060600060045467ffffffffffffffff811115612da257612da26138f3565b604051908082528060200260200182016040528015612de757816020015b6040805180820190915260008082526020820152815260200190600190039081612dc05790505b50905060005b8151811015610b0d5760086000612e05836001613f28565b815260208082019290925260409081016000208151808301909252805482526001015460ff161515918101919091528251839083908110612e4857612e48613922565b60200260200101819052508080612e5e90613980565b915050612ded565b6001612e718161305e565b811580612e7f575060045482115b15612eb6576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020908152604091829020600101805460ff811680157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090921682179092559251928352917f201d03f13a7e2a288f586fc6565e0f7470445b13d1903a8799b384ead54ab896910161286b565b612f32613090565b63389a75e1600c52806000526020600c208054421115612f5a57636f5e88186000526004601cfd5b60009055610e3881613236565b6001612f728161305e565b73ffffffffffffffffffffffffffffffffffffffff8216612fbf576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a90600090a3505050565b61303f613090565b8060601b61305557637448fbae6000526004601cfd5b610e3881613236565b638b78c6d8600c5233600052806020600c205416610e38576382b429006000526004601cfd5b610e4d828260006132f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611991576382b429006000526004601cfd5b610e4d828260016132f7565b60005460ff1615611991576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051600190836000526020830151604052604083510361316457604083015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660605261318a565b604183510361318557606083015160001a602052604083015160605261318a565b600091505b6020600160806000855afa5191503d6131ab57638baa579f6000526004601cfd5b600060605260405292915050565b6131c1613350565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6132a46130d2565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861320c3390565b638b78c6d8600c52826000526020600c20805483811783613319575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b60005460ff16611991576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252606080825260208201529081016000815260200160008152602001600061ffff1681526020016133e76040518060800160405280600081526020016000815260200160008152602001600081525090565b8152602001606081525090565b82805482825590600052602060002090810192821561342f579160200282015b8281111561342f578235825591602001919060010190613414565b5061343b92915061345d565b5090565b6040518060c001604052806006906020820280368337509192915050565b5b8082111561343b576000815560010161345e565b803573ffffffffffffffffffffffffffffffffffffffff8116811461349657600080fd5b919050565b6000602082840312156134ad57600080fd5b6134b682613472565b9392505050565b600081518084526020808501945080840160005b838110156134ed578151875295820195908201906001016134d1565b509495945050505050565b6020815260006134b660208301846134bd565b60006020828403121561351d57600080fd5b5035919050565b8151815260208083015115159082015260408101610e6a565b60008060006060848603121561355257600080fd5b61355b84613472565b95602085013595506040909401359392505050565b60008083601f84011261358257600080fd5b50813567ffffffffffffffff81111561359a57600080fd5b6020830191508360208260051b85010111156135b557600080fd5b9250929050565b600080602083850312156135cf57600080fd5b823567ffffffffffffffff8111156135e657600080fd5b6135f285828601613570565b90969095509350505050565b6000806040838503121561361157600080fd5b61361a83613472565b946020939093013593505050565b60078110610e3857600080fd5b60008083601f84011261364757600080fd5b50813567ffffffffffffffff81111561365f57600080fd5b6020830191508360208285010111156135b557600080fd5b60008060008060008060a0878903121561369057600080fd5b86359550602087013594506040870135935060608701356136b081613628565b9250608087013567ffffffffffffffff8111156136cc57600080fd5b6136d889828a01613635565b979a9699509497509295939492505050565b6000806000604084860312156136ff57600080fd5b83359250602084013567ffffffffffffffff81111561371d57600080fd5b61372986828701613570565b9497909650939450505050565b8015158114610e3857600080fd5b6000806040838503121561375757600080fd5b82359150602083013561376981613736565b809150509250929050565b60008060008060006080868803121561378c57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8111156137b857600080fd5b6137c488828901613635565b969995985093965092949392505050565b60008060008060008060a087890312156137ee57600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156136cc57600080fd5b6000806040838503121561383457600080fd5b8235915061384460208401613472565b90509250929050565b60008060008060006080868803121561386557600080fd5b8535945060208601359350604086013561387e81613628565b9250606086013567ffffffffffffffff8111156137b857600080fd5b602080825282518282018190526000919060409081850190868401855b828110156138e6576138d6848351805182526020908101511515910152565b92840192908501906001016138b7565b5091979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139b1576139b1613951565b5060010190565b6000602082840312156139ca57600080fd5b5051919050565b60405160e0810167ffffffffffffffff811182821017156139f4576139f46138f3565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a4157613a416138f3565b604052919050565b600082601f830112613a5a57600080fd5b815167ffffffffffffffff811115613a7457613a746138f3565b6020613aa6817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116016139fa565b8281528582848701011115613aba57600080fd5b60005b83811015613ad8578581018301518282018401528201613abd565b506000928101909101919091529392505050565b80516003811061349657600080fd5b805161349681613628565b805161ffff8116811461349657600080fd5b600060808284031215613b2a57600080fd5b6040516080810181811067ffffffffffffffff82111715613b4d57613b4d6138f3565b8060405250809150825181526020830151602082015260408301516040820152606083015160608201525092915050565b600082601f830112613b8f57600080fd5b8151602067ffffffffffffffff821115613bab57613bab6138f3565b8160051b613bba8282016139fa565b9283528481018201928281019087851115613bd457600080fd5b83870192505b84831015613bfa57613beb83613b06565b82529183019190830190613bda565b979650505050505050565b600060208284031215613c1757600080fd5b815167ffffffffffffffff80821115613c2f57600080fd5b908301906101408286031215613c4457600080fd5b613c4c6139d1565b825182811115613c5b57600080fd5b613c6787828601613a49565b825250602083015182811115613c7c57600080fd5b613c8887828601613a49565b602083015250613c9a60408401613aec565b6040820152613cab60608401613afb565b6060820152613cbc60808401613b06565b6080820152613cce8660a08501613b18565b60a082015261012083015182811115613ce657600080fd5b613cf287828601613b7e565b60c08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020815281602082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613d6957600080fd5b8260051b80856040850137919091016040019392505050565b60078110613db9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60f81b9052565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008660601b168152846014820152836034820152826054820152613e076074820183613d82565b7f4353554300000000000000000000000000000000000000000000000000000000607582015260790195945050505050565b81810381811115610e6a57610e6a613951565b6000610100808352613e60818401876134bd565b91505060208083018560005b6006811015613e8957815183529183019190830190600101613e6c565b5050505073ffffffffffffffffffffffffffffffffffffffff831660e0830152949350505050565b8082028115828204841417610e6a57610e6a613951565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613f0657613f06613ec8565b500490565b600060208284031215613f1d57600080fd5b81516134b681613736565b80820180821115610e6a57610e6a613951565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b168152836014820152826034820152613f7c6054820183613d82565b7f43554300000000000000000000000000000000000000000000000000000000006055820152605801949350505050565b600082613fbc57613fbc613ec8565b50069056fea264697066735822122021a3887e12303894c8ce3cdf21fc26c12690e96c0773c6d1029c39f145cf9b5464736f6c6343000814003300000000000000000000000051a16e6aec2924e8886fc323618876e3ed0e4de50000000000000000000000001facd50481d827d7d342d79278b9c5a1f9eb6cd70000000000000000000000003dba8332729cb351a15d9bceb4d48549362694ff000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d700000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a8000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac10000000000000000000000000bf88aa6ce002f96102f40de390d04e63738b0390000000000000000000000004131ae1e157c91fe083bdcf857a230fb79ac903a000000000000000000000000abb8621b2f4fb61f083b9f2a033a40086db9030d
Deployed Bytecode
0x6080604052600436106103135760003560e01c8063715018a61161019a578063addc831e116100e1578063eb6be5be1161008a578063f188e7f611610064578063f188e7f6146109ed578063f2fde38b14610a21578063fee81cf414610a3457600080fd5b8063eb6be5be1461099a578063f04e283e146109ba578063f0f44260146109cd57600080fd5b8063bad956a0116100bb578063bad956a0146108f7578063c353d89f1461092b578063e99dcb881461094d57600080fd5b8063addc831e14610897578063b099ae1e146108b7578063b52f106f146108d757600080fd5b80638614c08a1161014357806397d757761161011d57806397d7577614610837578063a51898101461086b578063ac3692021461088157600080fd5b80638614c08a146107c35780638da5cb5b146107e35780638dedf7271461081757600080fd5b80637f874928116101745780637f874928146107535780638303cdd0146107735780638456cb59146107ae57600080fd5b8063715018a6146106f7578063793eac56146106ff5780637afb9b1d1461071f57600080fd5b80632de948071161025e57806354d1f13d1161020757806361d027b3116101e157806361d027b31461067d578063684931ed146106aa5780636c19e783146106d757600080fd5b806354d1f13d1461063d578063560e8ad9146106455780635c975abb1461066557600080fd5b806348c622d91161023857806348c622d9146105d35780634a4ee7b1146105f3578063514e62fc1461060657600080fd5b80632de948071461055d57806335dfa2361461059e5780633f4ba83a146105be57600080fd5b80631b65c949116102c0578063238ac9331161029a578063238ac9331461050857806325692962146105355780632954eb9e1461053d57600080fd5b80631b65c949146104835780631c10893f146104d55780631cd64df4146104e857600080fd5b80631284bc0a116102f15780631284bc0a1461040d57806313d886601461044e578063183a4f6e1461047057600080fd5b806302678ad614610318578063063395b0146103805780630eeb607f146103a2575b600080fd5b34801561032457600080fd5b5061036b61033336600461349b565b73ffffffffffffffffffffffffffffffffffffffff166000908152600960209081526040808320600454845290915290205460ff1690565b60405190151581526020015b60405180910390f35b34801561038c57600080fd5b50610395610a67565b60405161037791906134f8565b3480156103ae57600080fd5b506104006103bd36600461350b565b6040805180820190915260008082526020820152506000908152600860209081526040918290208251808401909352805483526001015460ff1615159082015290565b6040516103779190613524565b34801561041957600080fd5b5061036b61042836600461353d565b600a60209081526000938452604080852082529284528284209052825290205460ff1681565b34801561045a57600080fd5b5061046e6104693660046135bc565b610b13565b005b61046e61047e36600461350b565b610e2e565b34801561048f57600080fd5b506002546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610377565b61046e6104e33660046135fe565b610e3b565b3480156104f457600080fd5b5061036b6105033660046135fe565b610e51565b34801561051457600080fd5b506005546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b61046e610e70565b34801561054957600080fd5b5061046e610558366004613677565b610ec0565b34801561056957600080fd5b5061059061057836600461349b565b638b78c6d8600c908152600091909152602090205490565b604051908152602001610377565b3480156105aa57600080fd5b5061046e6105b93660046136ea565b611270565b3480156105ca57600080fd5b5061046e61140b565b3480156105df57600080fd5b5061046e6105ee366004613744565b61141e565b61046e6106013660046135fe565b611518565b34801561061257600080fd5b5061036b6106213660046135fe565b638b78c6d8600c90815260009290925260209091205416151590565b61046e61152a565b34801561065157600080fd5b5061046e61066036600461350b565b611566565b34801561067157600080fd5b5060005460ff1661036b565b34801561068957600080fd5b506006546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156106b657600080fd5b506003546104b09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156106e357600080fd5b5061046e6106f236600461349b565b6118af565b61046e61197f565b34801561070b57600080fd5b5061046e61071a366004613774565b611993565b34801561072b57600080fd5b506104b07f000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac181565b34801561075f57600080fd5b5061046e61076e3660046137d5565b611ca3565b34801561077f57600080fd5b5061036b61078e3660046135fe565b600960209081526000928352604080842090915290825290205460ff1681565b3480156107ba57600080fd5b5061046e612058565b3480156107cf57600080fd5b5061046e6107de366004613821565b61206b565b3480156107ef57600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546104b0565b34801561082357600080fd5b5061046e61083236600461384d565b61242e565b34801561084357600080fd5b506104b07f000000000000000000000000430000000000000000000000000000000000000281565b34801561087757600080fd5b5061059060075481565b34801561088d57600080fd5b5061059060045481565b3480156108a357600080fd5b5061046e6108b236600461350b565b6127ea565b3480156108c357600080fd5b5061046e6108d23660046135fe565b612878565b3480156108e357600080fd5b5061046e6108f2366004613774565b61298f565b34801561090357600080fd5b506104b07f00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a881565b34801561093757600080fd5b50610940612d83565b604051610377919061389a565b34801561095957600080fd5b50604080518082018252600080825260209182018190526004548152600882528290208251808401909352805483526001015460ff16151590820152610400565b3480156109a657600080fd5b5061046e6109b536600461350b565b612e66565b61046e6109c836600461349b565b612f2a565b3480156109d957600080fd5b5061046e6109e836600461349b565b612f67565b3480156109f957600080fd5b506104b07f000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d781565b61046e610a2f36600461349b565b613037565b348015610a4057600080fd5b50610590610a4f36600461349b565b63389a75e1600c908152600091909152602090205490565b60015460609060009067ffffffffffffffff811115610a8857610a886138f3565b604051908082528060200260200182016040528015610ab1578160200160208202803683370190505b50905060005b8151811015610b0d5760018181548110610ad357610ad3613922565b9060005260206000200154828281518110610af057610af0613922565b602090810291909101015280610b0581613980565b915050610ab7565b50919050565b6001610b1e8161305e565b6000829003610b59576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac173ffffffffffffffffffffffffffffffffffffffff1663c3702fa76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bea91906139b8565b9050610bf461338c565b6000805b85811015610ddf576000878783818110610c1457610c14613922565b9050602002013590508060001480610c2b57508481115b15610c62576040517fadb070da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8083901c600116600103610ca2576040517f2ba6e3e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fabb05174000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac173ffffffffffffffffffffffffffffffffffffffff169063abb0517490602401600060405180830381865afa158015610d2d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610d739190810190613c05565b9350600184604001516002811115610d8d57610d8d613d01565b14610dc4576040517f7dbbb63500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001901b919091179080610dd781613980565b915050610bf8565b50610dec600187876133f4565b507fc8b9ea2d5ab30c96c1b241d2e00783f61a129991e28be275597f70900182c2de8686604051610e1e929190613d30565b60405180910390a1505050505050565b610e383382613084565b50565b610e43613090565b610e4d82826130c6565b5050565b638b78c6d8600c90815260008390526020902054811681145b92915050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610ec86130d2565b851580610ed6575060045486115b15610f0d576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000836006811115610f2157610f21613d01565b03610f58576040517faae1f34100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610fb73388888888604051602001610f76959493929190613dc0565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691611016918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614611063576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208a8452825280832089845290915290205460ff16156110c0576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208a84528252808320898452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155815181815280830190925290918281019080368337019050509050858160008151811061113d5761113d613922565b60200260200101818152505061115161343f565b61271081600188600681111561116957611169613d01565b6111739190613e39565b6006811061118357611183613922565b60200201526040517f03728ca300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a816906303728ca3906111fe90859085903390600401613e4c565b600060405180830381600087803b15801561121857600080fd5b505af115801561122c573d6000803e3d6000fd5b50506040518a81523392507f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241915060200160405180910390a2505050505050505050565b600161127b8161305e565b831580611289575060045484115b156112c0576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008290036112fb576040517f0f59b9ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526008602090815260408083208151808301909252805482526001015460ff16151591810191909152905b8381101561140357600085858381811061134657611346613922565b905060200201602081019061135b919061349b565b73ffffffffffffffffffffffffffffffffffffffff811660008181526009602090815260408083208c84529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551919250907f940206c6f5a27418505bf4749a3c0a97239e332c74cae71b8d2f471f2cb6f367906113e8908690613524565b60405180910390a250806113fb81613980565b91505061132a565b505050505050565b60016114168161305e565b610e386131b9565b60016114298161305e565b82600003611462576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060046000815461147390613980565b9182905550604080518082018252868152851515602080830191825260008581526008909152839020825181559051600190910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905590519192509082907f63d85844f48ee89556393c62467a122813caa566395ddbfd64f441bfaae926f190611509908490613524565b60405180910390a25050505050565b611520613090565b610e4d8282613084565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b61156e6130d2565b80158061157c575060045481115b156115b3576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260096020908152604080832084845290915290205460ff1615611608576040517fb8182bab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600860209081526040918290208251808401909352805483526001015460ff16151590820181905261166b576040517f9c45da5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061271060075483600001516116829190613eb1565b61168c9190613ef7565b9050801561173b576040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d773ffffffffffffffffffffffffffffffffffffffff16906379cc679090604401600060405180830381600087803b15801561172257600080fd5b505af1158015611736573d6000803e3d6000fd5b505050505b600654825173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d78116926323b872dd9233929190911690611791908690613e39565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064016020604051808303816000875af115801561180a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182e9190613f0b565b503360008181526009602090815260408083208784529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f940206c6f5a27418505bf4749a3c0a97239e332c74cae71b8d2f471f2cb6f367906118a2908590613524565b60405180910390a2505050565b60016118ba8161305e565b73ffffffffffffffffffffffffffffffffffffffff8216611907576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb90600090a3505050565b611987613090565b6119916000613236565b565b61199b6130d2565b8415806119a9575060045485115b156119e0576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810186905260548101859052607481018490527f43470000000000000000000000000000000000000000000000000000000000006094820152600090611a5890609601610f76565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691611ab7918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614611b04576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a60209081526040808320898452825280832088845290915290205460ff1615611b61576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600a602090815260408083208a845282528083208984529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810191909152602481018590527f000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d773ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c659190613f0b565b5060405185815233907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f72419060200160405180910390a2505050505050565b611cab6130d2565b851580611cb9575060045486115b15611cf0576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481018790526054810186905260748101859052609481018490527f435000000000000000000000000000000000000000000000000000000000000060b4820152600090611d6f9060b601610f76565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691611dce918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614611e1b576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208a8452825280832089845290915290205460ff1615611e78576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600a602090815260408083208b845282528083208a845290915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560025490517f7094cc22000000000000000000000000000000000000000000000000000000008152600481019390935260248301889052909173ffffffffffffffffffffffffffffffffffffffff90911690637094cc2290604401602060405180830381865afa158015611f3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6091906139b8565b60025490915073ffffffffffffffffffffffffffffffffffffffff166335aa2c8c3388611f8d8986613f28565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff9093166004840152602483019190915260448201526064015b600060405180830381600087803b15801561200157600080fd5b505af1158015612015573d6000803e3d6000fd5b50506040518981523392507f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241915060200160405180910390a25050505050505050565b60016120638161305e565b610e3861329c565b6120736130d2565b811580612081575060045482115b156120b8576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612105576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116600090815260096020908152604080832085845290915290205460ff1615612170576040517fb8182bab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600860209081526040918290208251808401909352805483526001015460ff1615159082018190526121d3576040517f9c45da5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061271060075483600001516121ea9190613eb1565b6121f49190613ef7565b905080156122a3576040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d773ffffffffffffffffffffffffffffffffffffffff16906379cc679090604401600060405180830381600087803b15801561228a57600080fd5b505af115801561229e573d6000803e3d6000fd5b505050505b600654825173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d78116926323b872dd92339291909116906122f9908690613e39565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123969190613f0b565b5073ffffffffffffffffffffffffffffffffffffffff831660008181526009602090815260408083208884529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f940206c6f5a27418505bf4749a3c0a97239e332c74cae71b8d2f471f2cb6f36790612420908590613524565b60405180910390a250505050565b6124366130d2565b841580612444575060045485115b1561247b576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083600681111561248f5761248f613d01565b036124c6576040517faae1f34100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006124e233878787604051602001610f769493929190613f3b565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691612541918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff161461258e576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a60209081526040808320898452825280832088845290915290205460ff16156125eb576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208984528252808320888452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558151818152808301909252909182810190803683370190505090506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663055877756040518163ffffffff1660e01b81526004016020604051808303816000875af11580156126c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126e991906139b8565b60018054919250906126fb9083613fad565b8154811061270b5761270b613922565b90600052602060002001548260008151811061272957612729613922565b60200260200101818152505061273d61343f565b61271081600189600681111561275557612755613d01565b61275f9190613e39565b6006811061276f5761276f613922565b60200201526040517f03728ca300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a816906303728ca3906111fe90869085903390600401613e4c565b60016127f58161305e565b612710821115612831576040517fc6cc5d7f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780549083905560408051828152602081018590527f5fd4dd55bd00e4ef8693a73e37974145a97ddf1063426ef2b6d5afcc2d4a949791015b60405180910390a1505050565b60016128838161305e565b73ffffffffffffffffffffffffffffffffffffffff83166128d0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d7169063a9059cbb906044016020604051808303816000875af1158015612965573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129899190613f0b565b50505050565b6129976130d2565b8415806129a5575060045485115b156129dc576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026040517fabb05174000000000000000000000000000000000000000000000000000000008152600481018590527f000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac173ffffffffffffffffffffffffffffffffffffffff169063abb0517490602401600060405180830381865afa158015612a69573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612aaf9190810190613c05565b604001516002811115612ac457612ac4613d01565b14612afb576040517fadb070da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810186905260548101859052607481018490527f43414300000000000000000000000000000000000000000000000000000000006094820152600090612b7390609701610f76565b600554604080516020601f870181900481028201810190925285815292935073ffffffffffffffffffffffffffffffffffffffff90911691612bd2918690869081908401838280828437600092019190915250869392505061310f9050565b73ffffffffffffffffffffffffffffffffffffffff1614612c1f576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a60209081526040808320898452825280832088845290915290205460ff1615612c7c576040517fbee3d04c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602090815260408083208984528252808320888452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558151818152808301909252909182810190803683370190505090508481600081518110612cf957612cf9613922565b602002602001018181525050612d0d61343f565b6040517f03728ca300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a816906303728ca390611fe790859085903390600401613e4c565b6060600060045467ffffffffffffffff811115612da257612da26138f3565b604051908082528060200260200182016040528015612de757816020015b6040805180820190915260008082526020820152815260200190600190039081612dc05790505b50905060005b8151811015610b0d5760086000612e05836001613f28565b815260208082019290925260409081016000208151808301909252805482526001015460ff161515918101919091528251839083908110612e4857612e48613922565b60200260200101819052508080612e5e90613980565b915050612ded565b6001612e718161305e565b811580612e7f575060045482115b15612eb6576040517f3bded03400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020908152604091829020600101805460ff811680157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090921682179092559251928352917f201d03f13a7e2a288f586fc6565e0f7470445b13d1903a8799b384ead54ab896910161286b565b612f32613090565b63389a75e1600c52806000526020600c208054421115612f5a57636f5e88186000526004601cfd5b60009055610e3881613236565b6001612f728161305e565b73ffffffffffffffffffffffffffffffffffffffff8216612fbf576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a90600090a3505050565b61303f613090565b8060601b61305557637448fbae6000526004601cfd5b610e3881613236565b638b78c6d8600c5233600052806020600c205416610e38576382b429006000526004601cfd5b610e4d828260006132f7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611991576382b429006000526004601cfd5b610e4d828260016132f7565b60005460ff1615611991576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051600190836000526020830151604052604083510361316457604083015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660605261318a565b604183510361318557606083015160001a602052604083015160605261318a565b600091505b6020600160806000855afa5191503d6131ab57638baa579f6000526004601cfd5b600060605260405292915050565b6131c1613350565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6132a46130d2565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861320c3390565b638b78c6d8600c52826000526020600c20805483811783613319575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b60005460ff16611991576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252606080825260208201529081016000815260200160008152602001600061ffff1681526020016133e76040518060800160405280600081526020016000815260200160008152602001600081525090565b8152602001606081525090565b82805482825590600052602060002090810192821561342f579160200282015b8281111561342f578235825591602001919060010190613414565b5061343b92915061345d565b5090565b6040518060c001604052806006906020820280368337509192915050565b5b8082111561343b576000815560010161345e565b803573ffffffffffffffffffffffffffffffffffffffff8116811461349657600080fd5b919050565b6000602082840312156134ad57600080fd5b6134b682613472565b9392505050565b600081518084526020808501945080840160005b838110156134ed578151875295820195908201906001016134d1565b509495945050505050565b6020815260006134b660208301846134bd565b60006020828403121561351d57600080fd5b5035919050565b8151815260208083015115159082015260408101610e6a565b60008060006060848603121561355257600080fd5b61355b84613472565b95602085013595506040909401359392505050565b60008083601f84011261358257600080fd5b50813567ffffffffffffffff81111561359a57600080fd5b6020830191508360208260051b85010111156135b557600080fd5b9250929050565b600080602083850312156135cf57600080fd5b823567ffffffffffffffff8111156135e657600080fd5b6135f285828601613570565b90969095509350505050565b6000806040838503121561361157600080fd5b61361a83613472565b946020939093013593505050565b60078110610e3857600080fd5b60008083601f84011261364757600080fd5b50813567ffffffffffffffff81111561365f57600080fd5b6020830191508360208285010111156135b557600080fd5b60008060008060008060a0878903121561369057600080fd5b86359550602087013594506040870135935060608701356136b081613628565b9250608087013567ffffffffffffffff8111156136cc57600080fd5b6136d889828a01613635565b979a9699509497509295939492505050565b6000806000604084860312156136ff57600080fd5b83359250602084013567ffffffffffffffff81111561371d57600080fd5b61372986828701613570565b9497909650939450505050565b8015158114610e3857600080fd5b6000806040838503121561375757600080fd5b82359150602083013561376981613736565b809150509250929050565b60008060008060006080868803121561378c57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8111156137b857600080fd5b6137c488828901613635565b969995985093965092949392505050565b60008060008060008060a087890312156137ee57600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156136cc57600080fd5b6000806040838503121561383457600080fd5b8235915061384460208401613472565b90509250929050565b60008060008060006080868803121561386557600080fd5b8535945060208601359350604086013561387e81613628565b9250606086013567ffffffffffffffff8111156137b857600080fd5b602080825282518282018190526000919060409081850190868401855b828110156138e6576138d6848351805182526020908101511515910152565b92840192908501906001016138b7565b5091979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139b1576139b1613951565b5060010190565b6000602082840312156139ca57600080fd5b5051919050565b60405160e0810167ffffffffffffffff811182821017156139f4576139f46138f3565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a4157613a416138f3565b604052919050565b600082601f830112613a5a57600080fd5b815167ffffffffffffffff811115613a7457613a746138f3565b6020613aa6817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116016139fa565b8281528582848701011115613aba57600080fd5b60005b83811015613ad8578581018301518282018401528201613abd565b506000928101909101919091529392505050565b80516003811061349657600080fd5b805161349681613628565b805161ffff8116811461349657600080fd5b600060808284031215613b2a57600080fd5b6040516080810181811067ffffffffffffffff82111715613b4d57613b4d6138f3565b8060405250809150825181526020830151602082015260408301516040820152606083015160608201525092915050565b600082601f830112613b8f57600080fd5b8151602067ffffffffffffffff821115613bab57613bab6138f3565b8160051b613bba8282016139fa565b9283528481018201928281019087851115613bd457600080fd5b83870192505b84831015613bfa57613beb83613b06565b82529183019190830190613bda565b979650505050505050565b600060208284031215613c1757600080fd5b815167ffffffffffffffff80821115613c2f57600080fd5b908301906101408286031215613c4457600080fd5b613c4c6139d1565b825182811115613c5b57600080fd5b613c6787828601613a49565b825250602083015182811115613c7c57600080fd5b613c8887828601613a49565b602083015250613c9a60408401613aec565b6040820152613cab60608401613afb565b6060820152613cbc60808401613b06565b6080820152613cce8660a08501613b18565b60a082015261012083015182811115613ce657600080fd5b613cf287828601613b7e565b60c08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020815281602082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613d6957600080fd5b8260051b80856040850137919091016040019392505050565b60078110613db9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60f81b9052565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008660601b168152846014820152836034820152826054820152613e076074820183613d82565b7f4353554300000000000000000000000000000000000000000000000000000000607582015260790195945050505050565b81810381811115610e6a57610e6a613951565b6000610100808352613e60818401876134bd565b91505060208083018560005b6006811015613e8957815183529183019190830190600101613e6c565b5050505073ffffffffffffffffffffffffffffffffffffffff831660e0830152949350505050565b8082028115828204841417610e6a57610e6a613951565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613f0657613f06613ec8565b500490565b600060208284031215613f1d57600080fd5b81516134b681613736565b80820180821115610e6a57610e6a613951565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b168152836014820152826034820152613f7c6054820183613d82565b7f43554300000000000000000000000000000000000000000000000000000000006055820152605801949350505050565b600082613fbc57613fbc613ec8565b50069056fea264697066735822122021a3887e12303894c8ce3cdf21fc26c12690e96c0773c6d1029c39f145cf9b5464736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000051a16e6aec2924e8886fc323618876e3ed0e4de50000000000000000000000001facd50481d827d7d342d79278b9c5a1f9eb6cd70000000000000000000000003dba8332729cb351a15d9bceb4d48549362694ff000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d700000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a8000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac10000000000000000000000000bf88aa6ce002f96102f40de390d04e63738b0390000000000000000000000004131ae1e157c91fe083bdcf857a230fb79ac903a000000000000000000000000abb8621b2f4fb61f083b9f2a033a40086db9030d
-----Decoded View---------------
Arg [0] : _gameMaster (address): 0x51a16E6AEc2924e8886fc323618876e3ED0e4dE5
Arg [1] : _signer (address): 0x1facD50481D827D7d342D79278B9C5A1F9eB6CD7
Arg [2] : _treasury (address): 0x3DbA8332729cB351a15d9bCEB4d48549362694ff
Arg [3] : _glory (address): 0xd582879453337BD149Ae53EC2092B0af5281d1D7
Arg [4] : _gameCards (address): 0x10FE37BAC405B209f83FF523Fb8D00C0c3F508a8
Arg [5] : _baseCards (address): 0xc8607C5BefA7A7567ca78040bA5C36d181243ac1
Arg [6] : _packShop (address): 0x0BF88Aa6Ce002F96102F40De390D04e63738b039
Arg [7] : _seeder (address): 0x4131aE1e157c91fe083BdCf857A230fb79Ac903a
Arg [8] : _blastGovernor (address): 0xAbb8621b2F4FB61f083b9f2a033A40086DB9030d
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000051a16e6aec2924e8886fc323618876e3ed0e4de5
Arg [1] : 0000000000000000000000001facd50481d827d7d342d79278b9c5a1f9eb6cd7
Arg [2] : 0000000000000000000000003dba8332729cb351a15d9bceb4d48549362694ff
Arg [3] : 000000000000000000000000d582879453337bd149ae53ec2092b0af5281d1d7
Arg [4] : 00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a8
Arg [5] : 000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac1
Arg [6] : 0000000000000000000000000bf88aa6ce002f96102f40de390d04e63738b039
Arg [7] : 0000000000000000000000004131ae1e157c91fe083bdcf857a230fb79ac903a
Arg [8] : 000000000000000000000000abb8621b2f4fb61f083b9f2a033a40086db9030d
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.