Source Code
Latest 25 from a total of 2,959 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Buy Pack | 13956740 | 378 days ago | IN | 0.0087 ETH | 0.00000526 | ||||
| Buy Pack | 13840696 | 380 days ago | IN | 0.0087 ETH | 0.00000453 | ||||
| Buy Pack | 13825893 | 381 days ago | IN | 0.0087 ETH | 0.00002015 | ||||
| Buy Pack | 13605228 | 386 days ago | IN | 0.0087 ETH | 0.00001013 | ||||
| Buy Pack | 13604811 | 386 days ago | IN | 0.0087 ETH | 0.00001052 | ||||
| Buy Pack | 13561666 | 387 days ago | IN | 0.0087 ETH | 0.00000585 | ||||
| Buy Pack | 13546794 | 387 days ago | IN | 0.0087 ETH | 0.00000492 | ||||
| Buy Pack | 13511645 | 388 days ago | IN | 0.0087 ETH | 0.00000869 | ||||
| Buy Pack | 13511595 | 388 days ago | IN | 0.0087 ETH | 0.00000909 | ||||
| Buy Pack | 13467375 | 389 days ago | IN | 0.0087 ETH | 0.00002263 | ||||
| Buy Pack | 13467361 | 389 days ago | IN | 0.0087 ETH | 0.00002178 | ||||
| Buy Pack | 13467343 | 389 days ago | IN | 0.0087 ETH | 0.0000213 | ||||
| Buy Pack | 13467188 | 389 days ago | IN | 0.0087 ETH | 0.00002138 | ||||
| Buy Pack | 13467168 | 389 days ago | IN | 0.0087 ETH | 0.00002167 | ||||
| Buy Pack | 13467158 | 389 days ago | IN | 0.0087 ETH | 0.00002179 | ||||
| Buy Pack | 13467144 | 389 days ago | IN | 0.0087 ETH | 0.00002174 | ||||
| Buy Pack | 13467122 | 389 days ago | IN | 0.0087 ETH | 0.00002204 | ||||
| Buy Pack | 13467101 | 389 days ago | IN | 0.0087 ETH | 0.00002179 | ||||
| Buy Pack | 13416766 | 390 days ago | IN | 0.0087 ETH | 0.00000509 | ||||
| Buy Pack | 13416753 | 390 days ago | IN | 0.0087 ETH | 0.00000518 | ||||
| Buy Pack | 13386729 | 391 days ago | IN | 0.0087 ETH | 0.00001289 | ||||
| Buy Pack | 13337732 | 392 days ago | IN | 0.0087 ETH | 0.0000154 | ||||
| Buy Pack | 13337343 | 392 days ago | IN | 0.0087 ETH | 0.00001314 | ||||
| Buy Pack | 13337270 | 392 days ago | IN | 0.0087 ETH | 0.00001146 | ||||
| Buy Pack | 13337085 | 392 days ago | IN | 0.0087 ETH | 0.00001465 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 13956740 | 378 days ago | 0.0087 ETH | ||||
| 13840696 | 380 days ago | 0.0087 ETH | ||||
| 13825893 | 381 days ago | 0.0087 ETH | ||||
| 13605228 | 386 days ago | 0.0087 ETH | ||||
| 13604811 | 386 days ago | 0.0087 ETH | ||||
| 13561666 | 387 days ago | 0.0087 ETH | ||||
| 13546794 | 387 days ago | 0.0087 ETH | ||||
| 13511645 | 388 days ago | 0.0087 ETH | ||||
| 13511595 | 388 days ago | 0.0087 ETH | ||||
| 13467375 | 389 days ago | 0.0087 ETH | ||||
| 13467361 | 389 days ago | 0.0087 ETH | ||||
| 13467343 | 389 days ago | 0.0087 ETH | ||||
| 13467188 | 389 days ago | 0.0087 ETH | ||||
| 13467168 | 389 days ago | 0.0087 ETH | ||||
| 13467158 | 389 days ago | 0.0087 ETH | ||||
| 13467144 | 389 days ago | 0.0087 ETH | ||||
| 13467122 | 389 days ago | 0.0087 ETH | ||||
| 13467101 | 389 days ago | 0.0087 ETH | ||||
| 13416766 | 390 days ago | 0.0087 ETH | ||||
| 13416753 | 390 days ago | 0.0087 ETH | ||||
| 13386729 | 391 days ago | 0.0087 ETH | ||||
| 13337732 | 392 days ago | 0.0087 ETH | ||||
| 13337343 | 392 days ago | 0.0087 ETH | ||||
| 13337270 | 392 days ago | 0.0087 ETH | ||||
| 13337085 | 392 days ago | 0.0087 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ETHPackShop
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 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 { SafeTransferLib } from "@solady/src/utils/SafeTransferLib.sol";
import { AccessRoles } from "./access/AccessRoles.sol";
import { IETHPackShop } from "./interfaces/IETHPackShop.sol";
import { IBaseCards } from "./interfaces/IBaseCards.sol";
import { IGameCards } from "./interfaces/IGameCards.sol";
import { ISeeder } from "./interfaces/ISeeder.sol";
import { IBlast } from "./interfaces/IBlast.sol";
/**
* @title ETHPackShop
* @notice This contract is responsible for handling all functionality related to packs. A Game Master can add
* packs which users can open to acquire tokenized game cards.
*/
contract ETHPackShop is IETHPackShop, OwnableRoles {
using SafeTransferLib for address;
using ECDSA for bytes32;
uint256 private constant _WEIGHT_SUM = 10_000;
uint256 private constant _BPS = 10_000;
uint256 private constant _MAX_BENEFICIARIES = 5;
mapping(uint256 packId => Pack pack) private _packs;
address[] private _beneficiaries;
uint256[] private _weights;
IBlast public immutable BLAST = IBlast(0x4300000000000000000000000000000000000002);
IGameCards public gameCards;
IBaseCards public baseCards;
ISeeder public seeder;
/**
* @inheritdoc IETHPackShop
*/
uint256 public nextPackId = 0;
/**
* @inheritdoc IETHPackShop
*/
address public signer;
/**
* @inheritdoc IETHPackShop
*/
mapping(address account => mapping(uint256 packId => uint256 purchases)) public packsPurchased;
/**
* @inheritdoc IETHPackShop
*/
mapping(address account => mapping(uint256 packId => uint256 claims)) public freePackClaims;
/**
* Maps a nonce to a used value.
*/
mapping(uint256 nonce => bool used) public nonceUsed;
constructor(
address _gameMaster,
address _seeder,
address _gameCards,
address _baseCards,
address _signer,
address _blastGovernor,
address[] memory __beneficiaries,
uint256[] memory __weights
) {
if (
_gameMaster == address(0) ||
_seeder == address(0) ||
_gameCards == address(0) ||
_baseCards == address(0) ||
_signer == address(0) ||
_blastGovernor == address(0)
) revert ZeroAddress();
if (__beneficiaries.length == 0 || __beneficiaries.length > _MAX_BENEFICIARIES) revert InvalidArrayLength();
if (__beneficiaries.length != __weights.length) revert ArrayLengthMismatch();
uint256 weightSum = 0;
for (uint256 i = 0; i < __weights.length; i++) {
address beneficiary = __beneficiaries[i];
uint256 weight = __weights[i];
if (beneficiary == address(0)) revert ZeroAddress();
if (weight == 0) revert InvalidWeight();
weightSum += weight;
}
if (weightSum != _WEIGHT_SUM) revert InvalidWeightSum();
_beneficiaries = __beneficiaries;
_weights = __weights;
BLAST.configureClaimableGas();
BLAST.configureGovernor({ _governor: _blastGovernor });
_initializeOwner({ newOwner: msg.sender });
_grantRoles({ user: _gameMaster, roles: AccessRoles.GAME_MASTER_ROLE });
gameCards = IGameCards(_gameCards);
baseCards = IBaseCards(_baseCards);
seeder = ISeeder(_seeder);
signer = _signer;
}
/**
* @inheritdoc IETHPackShop
*/
function buyPack(uint256 packId, bytes calldata signature) external payable checkOrigin {
if (packId >= nextPackId) revert NonExistentPackId();
Pack memory pack = _packs[packId];
if (pack.startTime > block.timestamp || pack.endTime < block.timestamp) revert SaleNotActive();
if (pack.supply == 0) revert PackSoldOut();
if (msg.value != pack.price) revert InvalidEtherAmount();
if (++packsPurchased[msg.sender][packId] > pack.purchaseLimit) revert OverPurchaseLimit();
_packs[packId].supply--;
if (pack.signerGated) {
bytes32 digest = keccak256(abi.encodePacked(msg.sender, packId)).toEthSignedMessageHash();
if (signer != digest.recover(signature)) revert SignerMismatch();
}
if (pack.price != 0 ether) {
for (uint256 i = 0; i < _beneficiaries.length; i++) {
uint256 share = msg.value * _weights[i] / _BPS;
_beneficiaries[i].safeTransferETH({ amount: share });
}
}
uint256[] memory newCardIds = _chooseCards(pack);
gameCards.mintCards({ cardIds: newCardIds, tierWeights: pack.tierWeights, receiver: msg.sender });
emit PackPurchased({ account: msg.sender, packId: packId });
}
/**
* @inheritdoc IETHPackShop
*/
function redeemPack(
uint256 packId,
uint256 nonce,
string calldata code,
bytes calldata signature
) external payable checkOrigin {
if (packId >= nextPackId) revert NonExistentPackId();
if (nonceUsed[nonce]) revert NonceUsed();
nonceUsed[nonce] = true;
bytes32 digest = keccak256(abi.encodePacked(msg.sender, packId, nonce, code)).toEthSignedMessageHash();
if (digest.recover(signature) != signer) revert SignerMismatch();
Pack memory pack = _packs[packId];
if (pack.startTime > block.timestamp || pack.endTime < block.timestamp) revert SaleNotActive();
if (pack.supply == 0) revert PackSoldOut();
if (msg.value != pack.price) revert InvalidEtherAmount();
if (++packsPurchased[msg.sender][packId] > pack.purchaseLimit) revert OverPurchaseLimit();
_packs[packId].supply--;
if (pack.price != 0 ether) {
for (uint256 i = 0; i < _beneficiaries.length; i++) {
uint256 share = msg.value * _weights[i] / _BPS;
_beneficiaries[i].safeTransferETH({ amount: share });
}
}
uint256[] memory newCardIds = _chooseCards(pack);
gameCards.mintCards({ cardIds: newCardIds, tierWeights: pack.tierWeights, receiver: msg.sender });
emit PackRedeemed({ account: msg.sender, packId: packId, code: code });
}
/**
* @inheritdoc IETHPackShop
*/
function claimPack(uint256 packId) external checkOrigin {
if (packId >= nextPackId) revert NonExistentPackId();
if (freePackClaims[msg.sender][packId] == 0) revert NoFreeClaims();
freePackClaims[msg.sender][packId]--;
Pack memory pack = _packs[packId];
uint256[] memory newCardIds = _chooseCards(pack);
gameCards.mintCards({ cardIds: newCardIds, tierWeights: pack.tierWeights, receiver: msg.sender });
emit PackClaimed({ account: msg.sender, packId: packId });
}
/**
* @inheritdoc IETHPackShop
*/
function addPack(Pack calldata newPack) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
_validatePack(newPack);
uint256 packId = nextPackId++;
_packs[packId] = newPack;
emit PackAdded(packId, newPack);
}
/**
* @inheritdoc IETHPackShop
*/
function addFreePackClaims(
address account,
uint256 packId,
uint256 amount
) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (packId >= nextPackId) revert NonExistentPackId();
freePackClaims[account][packId] = amount;
emit PackClaimsAdded(account, packId, amount);
}
/**
* @inheritdoc IETHPackShop
*/
function updatePack(uint256 packId, Pack calldata newPack) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (packId >= nextPackId) revert NonExistentPackId();
_validatePack(newPack);
Pack memory oldPack = _packs[packId];
_packs[packId] = newPack;
emit PackUpdated(packId, oldPack, newPack);
}
/**
* @inheritdoc IETHPackShop
*/
function setPackSupply(uint256 packId, uint256 amount) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (packId >= nextPackId) revert NonExistentPackId();
_packs[packId].supply = amount;
emit PackSupplyUpdated(packId, amount);
}
/**
* @inheritdoc IETHPackShop
*/
function setPackSaleWindow(uint256 packId, uint256 startTime, uint256 endTime) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (packId >= nextPackId) revert NonExistentPackId();
_packs[packId].startTime = startTime;
_packs[packId].endTime = endTime;
emit SaleWindowUpdated(packId, startTime, endTime);
}
/**
* @inheritdoc IETHPackShop
*/
function sunsetPack(uint256 packId) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (packId >= nextPackId) revert NonExistentPackId();
_packs[packId].startTime = 0;
_packs[packId].endTime = 0;
emit PackSunset(packId);
}
/**
* @inheritdoc IETHPackShop
*/
function rereleasePack(uint256 packId, uint256 endTime) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (packId >= nextPackId) revert NonExistentPackId();
if (endTime <= block.timestamp) revert InvalidEndTime();
_packs[packId].startTime = block.timestamp;
_packs[packId].endTime = endTime;
emit PackRereleased(packId, endTime);
}
/**
* @inheritdoc IETHPackShop
*/
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 IETHPackShop
*/
function setBaseCards(address newBaseCards) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newBaseCards == address(0)) revert ZeroAddress();
address oldBaseCards = address(baseCards);
baseCards = IBaseCards(newBaseCards);
emit BaseCardsUpdated(oldBaseCards, newBaseCards);
}
/**
* @inheritdoc IETHPackShop
*/
function setGameCards(address newGameCards) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newGameCards == address(0)) revert ZeroAddress();
address oldGameCards = address(gameCards);
gameCards = IGameCards(newGameCards);
emit GameCardsUpdated(oldGameCards, newGameCards);
}
/**
* @inheritdoc IETHPackShop
*/
function setSeeder(address newSeeder) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (newSeeder == address(0)) revert ZeroAddress();
address oldSeeder = address(seeder);
seeder = ISeeder(newSeeder);
emit SeederUpdated(oldSeeder, newSeeder);
}
/**
* @inheritdoc IETHPackShop
*/
function setBeneficiaries(
address[] calldata beneficiaries,
uint256[] calldata weights
) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (beneficiaries.length == 0 || beneficiaries.length > _MAX_BENEFICIARIES) revert InvalidArrayLength();
if (beneficiaries.length != weights.length) revert ArrayLengthMismatch();
uint256 weightSum = 0;
for (uint256 i = 0; i < weights.length; i++) {
address beneficary = beneficiaries[i];
uint256 weight = weights[i];
if (beneficary == address(0)) revert ZeroAddress();
if (weight == 0) revert InvalidWeight();
weightSum += weight;
}
if (weightSum != _WEIGHT_SUM) revert InvalidWeightSum();
address[] memory oldBeneficiaries = _beneficiaries;
_beneficiaries = beneficiaries;
_weights = weights;
emit BeneficiariesUpdated(oldBeneficiaries, beneficiaries, weights);
}
/**
* @inheritdoc IETHPackShop
*/
function withdraw(address receiver) external onlyRoles(AccessRoles.GAME_MASTER_ROLE) {
if (receiver == address(0)) revert ZeroAddress();
receiver.safeTransferETH({ amount: address(this).balance });
}
/**
* @inheritdoc IETHPackShop
*/
function packs(uint256 packId) external view returns (Pack memory) {
return _packs[packId];
}
/**
* @inheritdoc IETHPackShop
*/
function beneficiariesAndWeights() external view returns (address[] memory, uint256[] memory) {
return (_beneficiaries, _weights);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to chose `pack.pulls` amount of cards based on weightings.
* @param pack Respective `Pack` struct.
*/
function _chooseCards(Pack memory pack) internal returns (uint256[] memory) {
uint256[] memory chosenCards = new uint256[](pack.pulls);
uint256 ephemeralSeed = seeder.getAndUpdateGameSeed();
for (uint256 i = 0; i < pack.pulls; i++) {
uint256 cardRoll = (ephemeralSeed % _WEIGHT_SUM) + 1;
uint256 cumulativeCardWeight = 0;
for (uint256 j = 0; j < pack.cardWeights.length; j++) {
cumulativeCardWeight += pack.cardWeights[j];
if (cardRoll <= cumulativeCardWeight) {
chosenCards[i] = pack.cardIds[j];
break;
}
}
ephemeralSeed = uint256(keccak256(abi.encodePacked(ephemeralSeed, i)));
}
return chosenCards;
}
/**
* Function used to validate a `Pack` struct.
* @param pack Respective `Pack` struct to validate.
*/
function _validatePack(Pack calldata pack) internal view {
if (pack.cardIds.length != pack.cardWeights.length) revert ArrayLengthMismatch();
if (pack.cardIds.length == 0) revert ZeroLengthArray();
if (pack.pulls == 0) revert InvalidPullAmount();
if (pack.startTime >= pack.endTime) revert InvalidSaleWindow();
if (pack.supply == 0) revert InvalidPackSupply();
if (pack.purchaseLimit == 0) revert InvalidPurchaseLimit();
/// Validate `Pack.cardIds` and `Pack.cardWeights` by ensuring that the sum of weights is equal to `_WEIGHT_SUM`
/// and that all card IDs exist.
uint256 baseCardCount = baseCards.baseCardCount();
uint256 weightSum = 0;
for (uint256 i = 0; i < pack.cardWeights.length; i++) {
weightSum += pack.cardWeights[i];
uint256 cardId = pack.cardIds[i];
if (cardId == 0 || cardId > baseCardCount) revert NonExistentCardId();
}
if (weightSum != _WEIGHT_SUM) revert InvalidCardWeightSum();
/// Validate `Pack.tierWeights` by ensuring the sum of weights is equal to `_WEIGHT_SUM`.
weightSum = 0;
for (uint256 i = 0; i < pack.tierWeights.length; i++) {
weightSum += pack.tierWeights[i];
}
if (weightSum != _WEIGHT_SUM) revert InvalidWeightSum();
}
function _checkOrigin() internal view {
if (msg.sender != tx.origin) revert CallerNotOrigin();
}
modifier checkOrigin() {
_checkOrigin();
_;
}
}// 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
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for
/// the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul(
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}// 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 IETHPackShop
* @notice Interface for PackShop.
*/
interface IETHPackShop {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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 weights doesn't equal 10_000.
*/
error InvalidWeightSum();
/**
* Thrown when an invalid weight has been provided.
*/
error InvalidWeight();
/**
* 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 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();
/**
* Thrown when an input array is an invalid length.
*/
error InvalidArrayLength();
/**
* Thrown when an invalid Ether amount has been provided.
*/
error InvalidEtherAmount();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Struct encapsulating information related to a pack.
* @param price Price of a pack in native token.
* @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);
/**
* 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);
/**
* Emitted when beneficiaries are updated.
* @param oldBeneficiaries Old beneficiary addresses.
* @param newBeneficiaries New beneficiary addresses.
* @param newWeights New weights associated with each new beneficiary.
*/
event BeneficiariesUpdated(
address[] indexed oldBeneficiaries,
address[] indexed newBeneficiaries,
uint256[] indexed newWeights
);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function to purchase a pack.
* @param packId Unique pack identifier.
* @param signature Signed message digest.
*/
function buyPack(uint256 packId, bytes calldata signature) external payable;
/**
* 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 payable;
/**
* Function used to update the signer address.
* @param newSigner Newly desired signer address
*/
function setSigner(address newSigner) 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 set pack beneficiaries and weights.
* @param beneficiaries Array of beneficiary addresses.
* @param weights Array of weights associated with each beneficiary.
*/
function setBeneficiaries(
address[] calldata beneficiaries,
uint256[] calldata weights
) external;
/**
* Function used to withdraw native token from this contract.
* @param receiver Receiving address of the withdrawn funds.
*/
function withdraw(address receiver) external;
/**
* Function used to view the ID of the next added pack.
*/
function nextPackId() external view returns (uint256);
/**
* 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);
/**
* Function used to view the current beneficiaries and weights.
*/
function beneficiariesAndWeights() external view returns (address[] memory, uint256[] 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;
import { ICardAbilities } from "./ICardAbilities.sol";
import { IERC721AUpgradeable } from "@erc721a-upgradeable/interfaces/IERC721AUpgradeable.sol";
import { Game } from "../types/Game.sol";
/**
* @title IGameCards
* @notice Interface for GameCards.
*/
interface IGameCards is IERC721AUpgradeable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when the zero address is provided.
*/
error ZeroAddress();
/**
* Thrown when an input array of zero length is provided.
*/
error ZeroLengthArray();
/**
* Thrown when trying to access data for a non-existent token ID.
*/
error NonExistentTokenId();
/**
* Thrown when the caller is not the owner of the card.
*/
error CallerNotOwner();
/**
* Thrown when the specified level does not match the expected level.
*/
error CardLevelMismatch();
/**
* Thrown when the recovered signer does not match the expected signer.
*/
error SignerMismatch();
/**
* Thrown when an invalid card level is provided.
*/
error InvalidCardLevel();
/**
* Thrown when an invalid maximum card level is provided.
*/
error InvalidMaxLevel();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when a new player card is defined.
* @param tokenId Unique token identifier.
* @param newPlayerCard Information relating to the newly defined player card.
*/
event PlayerCardDefined(uint256 indexed tokenId, Game.PlayerCard newPlayerCard);
/**
* Emitted when the `Seeder` contract is updated.
* @param oldSeeder Old `Seeder` contract address.
* @param newSeeder New `Seeder` contract address.
*/
event SeederUpdated(address oldSeeder, address newSeeder);
/**
* Emitted when the `Abilities` contract is updated.
* @param oldAbilities Old `Abilities` contract address.
* @param newAbilities New `Abilities` contract address.
*/
event AbilitiesUpdated(address oldAbilities, address newAbilities);
/**
* Emitted when the `MetadataRenderer` contract is updated.
* @param oldMetadataRenderer Old `MetadataRenderer` contract address.
* @param newMetadataRenderer New `MetadataRenderer` contract address.
*/
event MetadataRendererUpdated(address oldMetadataRenderer, address newMetadataRenderer);
/**
* Emitted when the `signer` address is updated.
* @param oldSigner Old `signer` address.
* @param newSigner New `signer` address.
*/
event SignerUpdated(address indexed oldSigner, address indexed newSigner);
/**
* Emitted when the `baseCards` address is updated.
* @param oldBaseCards Old `baseCards` address.
* @param newBaseCards New `baseCards` address.
*/
event BaseCardsUpdated(address oldBaseCards, address newBaseCards);
/**
* Emitted when a player card is leveled.
* @param tokenId Unique card identifier.
* @param oldLevel Old card level.
* @param newLevel New card level.
*/
event LevelUp(uint256 indexed tokenId, uint256 oldLevel, uint256 newLevel);
/**
* Emitted when the maximum card level is updated.
* @param oldMaxLevel Old maximum card level.
* @param newMaxLevel New maximum card level.
*/
event MaxCardLevelUpdated(uint256 oldMaxLevel, uint256 newMaxLevel);
/**
* Emitted when level stat modifiers are updated.
* @param level Stat level being modified.
* @param oldStatModifiers Old stat modifiers for `level`.
* @param newStatModifiers New stat modifiers for `level`.
*/
event StatModifiersUpdated(uint256 indexed level, Game.Stats oldStatModifiers, Game.Stats newStatModifiers);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to view the total number of derivative base cards that have been minted.
* @param baseCardId Unique base card identifier.
*/
function serialNumbers(uint256 baseCardId) external view returns (uint256);
/**
* Function used to initialize the Cards contract.
* @param _owner Contract owner.
* @param _gameMaster Designed Game Master.
* @param _signer Signer address.
* @param _seeder Seeder contract.
* @param _baseCards BaseCards contract.
* @param _abilities Abilities contract.
* @param _metadataRenderer Metadata renderer contract.
* @param _blastGovernor Blast Governor contract.
*/
function initialize(
address _owner,
address _gameMaster,
address _signer,
address _seeder,
address _baseCards,
address _abilities,
address _metadataRenderer,
address _blastGovernor
) external;
/**
* Function used to mint new cards to the receiver.
* @param cardIds Unique card identifiers to mint.
* @param tierWeights Weightings associated with rolling a specific tier of card.
* @param receiver Address to mint the new cards to.
*/
function mintCards(uint256[] calldata cardIds, uint256[6] calldata tierWeights, address receiver) external;
/**
* Function used to incinerate a list of cards.
* @param tokenIds Array of card identifiers.
*/
function incinerate(uint256[] calldata tokenIds) external;
/**
* Function used to level up a card.
* @param tokenId Unique card identifier.
* @param newLevel Expected new level of the card.
* @param signature Signed message digest.
*/
function levelUpCard(uint256 tokenId, uint256 newLevel, bytes calldata signature) external;
/**
* Function used to set a new `Seeder` value.
* @param newSeeder New `Seeder` contract address.
*/
function setSeeder(address newSeeder) external;
/**
* Function used to set a new `BaseCards` value.
* @param newBaseCards New `BaseCards` contract address.
*/
function setBaseCards(address newBaseCards) external;
/**
* Function used to set a new `Abilities` value.
* @param newAbilities New `Abilities` contract address.
*/
function setAbilities(address newAbilities) external;
/**
* Function used to set a new `MetadataRenderer` value.
* @param newMetadataRenderer New `MetadataRenderer` contract address.
*/
function setMetadataRenderer(address newMetadataRenderer) external;
/**
* Function used to set a new `signer` address.
* @param newSigner New `signer` address value.
*/
function setSigner(address newSigner) external;
/**
* Function used to set stat modifiers for a specified card level.
* @param level Card level to set stat modifiers for.
* @param modifiers New stat modifiers for `level`.
*/
function setCardLevelModifiers(uint256 level, Game.Stats calldata modifiers) external;
/**
* Function used to set a new maximum card level.
* @param newMaxLevel New maximum card level value.
*/
function setMaxCardLevel(uint256 newMaxLevel) external;
/**
* Function used to view the `Game.PlayerCard` struct for a given token idenitifer.
* @param tokenId Unique token identifier.
*/
function playerCards(uint256 tokenId) external view returns (Game.PlayerCard memory);
/**
* Function used to view the current stat modifiers of a given card level.
* @param cardLevel Card level to check modifiers for.
*/
function statModifiers(uint256 cardLevel) external view returns (Game.Stats memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
/**
* @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;
/**
* @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.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
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 ICardAbilities
* @notice Interface for CardAbilities.
*/
interface ICardAbilities {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Thrown when a Ability input array of zero length is provided.
*/
error ZeroLengthArray();
/**
* Thrown when an undefined archetype is provided.
*/
error UndefinedArchetype();
/**
* Thrown when an empty ability name is provided.
*/
error EmptyName();
/**
* Thrown when an undefined AbilityStars value is provided.
*/
error UndefinedAbilityStars();
/**
* Thrown when the zero address is provided as input.
*/
error ZeroAddress();
/**
* Thrown when the sum of weights doesn't equal 10_000.
*/
error InvalidWeightSum();
/**
* Thrown when a non-existent ability ID is provided.
*/
error NonExistentAbilityId();
/**
* Thrown when `Game.CardTier.UNDEFINED` is provided when updating weights.
*/
error UndefinedCardTier();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ENUMS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Enum encapsulating the number of stars that can be associated with an ability.
*/
enum AbilityStars {
UNDEFINED,
ONE,
TWO,
THREE
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Struct encapsulating an Ability.
* @param name Name of the ability.
* @param stars Star tier.
* @param archetype Related archetype.
*/
struct Ability {
string name;
AbilityStars stars;
uint16 archetype;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Emitted when an ability is added.
* @param abilityId Unique ability identifier.
* @param newAbility The new ability that was added.
*/
event AbilityAdded(uint256 indexed abilityId, Ability newAbility);
/**
* Emitted when an ability is removed.
* @param abilityId Unique ability idenitfier.
* @param ability Ability that has been removed.
*/
event AbilityRemoved(uint256 indexed abilityId, Ability ability);
/**
* Emitted when the name of an ability is updated.
* @param abilityId Unique ability identifier.
* @param oldName Old ability name.
* @param newName New ability name.
*/
event AbilityNameUpdated(uint256 indexed abilityId, string oldName, string newName);
/**
* Emitted when card tier ability weights are updated.
* @param cardTier Game.CardTier value.
* @param oldWeights Old weight values.
* @param newWeights New weight values.
*/
event WeightsUpdated(Game.CardTier cardTier, uint256[3] oldWeights, uint256[3] newWeights);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/**
* Function used to view the total number of abilities.
*/
function abilityCount() external view returns (uint256);
/**
* Function used to add abilities.
* @param newAbilities Array of abilities to add.
*/
function addAbilities(Ability[] calldata newAbilities) external;
/**
* Function used to edit an already existing ability name.
* @param abilityId Unique ability identifier.
* @param newName Newly desired name value.
*/
function editAbilityName(uint256 abilityId, string calldata newName) external;
/**
* Function used to remove an ability.
* @param abilityId Unique ability idenitifer.
* @custom:note This function should be called with extreme caution as removing an ability already associated with a
* tokenized card break the game.
*/
function removeAbility(uint256 abilityId) external;
/**
* Function used to get abilities for a card.
* @param cardTier Tier of the card.
* @param archetypes Archetypes associated with the card.
* @param ephemeralSeed Seed used to "randomise" ability choices.
*/
function getCardAbilities(
Game.CardTier cardTier,
uint16[] calldata archetypes,
uint256 ephemeralSeed
) external view returns (uint256[3] memory abilities);
/**
* Function used to update card tier ability weights.
* @param cardTier Card tier to update weights for.
* @param updatedWeights Updated card tier weights.
*/
function updateWeights(Game.CardTier cardTier, uint256[3] calldata updatedWeights) external;
/**
* Function used to view the ability associated with an ID.
* @param abilityId Unique ability identifier.
*/
function idToAbility(uint256 abilityId) external view returns (Ability memory);
/**
* Function used to view the sorted abilities for a given archetype at a specified star tier.
* @param archetype Archetype of the unit.
* @param stars Star tier rating to lookup.
*/
function sortedAbilities(uint16 archetype, AbilityStars stars) external view returns (uint256[] memory);
/**
* Function used to view the star tier weights of a given card tier.
* @param cardTier Tier of card to check weights for.
*/
function weights(Game.CardTier cardTier) external view returns (uint256[3] memory);
}// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721AUpgradeable.sol';
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721AUpgradeable {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external payable;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}{
"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": 200
},
"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":"_seeder","type":"address"},{"internalType":"address","name":"_gameCards","type":"address"},{"internalType":"address","name":"_baseCards","type":"address"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_blastGovernor","type":"address"},{"internalType":"address[]","name":"__beneficiaries","type":"address[]"},{"internalType":"uint256[]","name":"__weights","type":"uint256[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"CallerNotOrigin","type":"error"},{"inputs":[],"name":"InvalidArrayLength","type":"error"},{"inputs":[],"name":"InvalidCardWeightSum","type":"error"},{"inputs":[],"name":"InvalidEndTime","type":"error"},{"inputs":[],"name":"InvalidEtherAmount","type":"error"},{"inputs":[],"name":"InvalidPackSupply","type":"error"},{"inputs":[],"name":"InvalidPullAmount","type":"error"},{"inputs":[],"name":"InvalidPurchaseLimit","type":"error"},{"inputs":[],"name":"InvalidSaleWindow","type":"error"},{"inputs":[],"name":"InvalidWeight","type":"error"},{"inputs":[],"name":"InvalidWeightSum","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoFreeClaims","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NonExistentCardId","type":"error"},{"inputs":[],"name":"NonExistentPackId","type":"error"},{"inputs":[],"name":"NonceUsed","type":"error"},{"inputs":[],"name":"OverPurchaseLimit","type":"error"},{"inputs":[],"name":"PackSoldOut","type":"error"},{"inputs":[],"name":"SaleNotActive","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":false,"internalType":"address","name":"oldBaseCards","type":"address"},{"indexed":false,"internalType":"address","name":"newBaseCards","type":"address"}],"name":"BaseCardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"oldBeneficiaries","type":"address[]"},{"indexed":true,"internalType":"address[]","name":"newBeneficiaries","type":"address[]"},{"indexed":true,"internalType":"uint256[]","name":"newWeights","type":"uint256[]"}],"name":"BeneficiariesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGameCards","type":"address"},{"indexed":false,"internalType":"address","name":"newGameCards","type":"address"}],"name":"GameCardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"},{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"pulls","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"purchaseLimit","type":"uint256"},{"internalType":"bool","name":"signerGated","type":"bool"},{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"},{"internalType":"uint256[]","name":"cardWeights","type":"uint256[]"},{"internalType":"uint256[6]","name":"tierWeights","type":"uint256[6]"}],"indexed":false,"internalType":"struct IETHPackShop.Pack","name":"newPack","type":"tuple"}],"name":"PackAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"}],"name":"PackClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PackClaimsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"}],"name":"PackPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"},{"indexed":false,"internalType":"string","name":"code","type":"string"}],"name":"PackRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"PackRereleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"}],"name":"PackSunset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PackSupplyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"packId","type":"uint256"},{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"pulls","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"purchaseLimit","type":"uint256"},{"internalType":"bool","name":"signerGated","type":"bool"},{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"},{"internalType":"uint256[]","name":"cardWeights","type":"uint256[]"},{"internalType":"uint256[6]","name":"tierWeights","type":"uint256[6]"}],"indexed":false,"internalType":"struct IETHPackShop.Pack","name":"oldPack","type":"tuple"},{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"pulls","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"purchaseLimit","type":"uint256"},{"internalType":"bool","name":"signerGated","type":"bool"},{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"},{"internalType":"uint256[]","name":"cardWeights","type":"uint256[]"},{"internalType":"uint256[6]","name":"tierWeights","type":"uint256[6]"}],"indexed":false,"internalType":"struct IETHPackShop.Pack","name":"newPack","type":"tuple"}],"name":"PackUpdated","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":"uint256","name":"packId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"SaleWindowUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSeeder","type":"address"},{"indexed":false,"internalType":"address","name":"newSeeder","type":"address"}],"name":"SeederUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":true,"internalType":"address","name":"newSigner","type":"address"}],"name":"SignerUpdated","type":"event"},{"inputs":[],"name":"BLAST","outputs":[{"internalType":"contract IBlast","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"packId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addFreePackClaims","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"pulls","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"purchaseLimit","type":"uint256"},{"internalType":"bool","name":"signerGated","type":"bool"},{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"},{"internalType":"uint256[]","name":"cardWeights","type":"uint256[]"},{"internalType":"uint256[6]","name":"tierWeights","type":"uint256[6]"}],"internalType":"struct IETHPackShop.Pack","name":"newPack","type":"tuple"}],"name":"addPack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseCards","outputs":[{"internalType":"contract IBaseCards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beneficiariesAndWeights","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"packId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"buyPack","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"packId","type":"uint256"}],"name":"claimPack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"packId","type":"uint256"}],"name":"freePackClaims","outputs":[{"internalType":"uint256","name":"claims","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameCards","outputs":[{"internalType":"contract IGameCards","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":[],"name":"nextPackId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"nonceUsed","outputs":[{"internalType":"bool","name":"used","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":[{"internalType":"uint256","name":"packId","type":"uint256"}],"name":"packs","outputs":[{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"pulls","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"purchaseLimit","type":"uint256"},{"internalType":"bool","name":"signerGated","type":"bool"},{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"},{"internalType":"uint256[]","name":"cardWeights","type":"uint256[]"},{"internalType":"uint256[6]","name":"tierWeights","type":"uint256[6]"}],"internalType":"struct IETHPackShop.Pack","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"packId","type":"uint256"}],"name":"packsPurchased","outputs":[{"internalType":"uint256","name":"purchases","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"packId","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"string","name":"code","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"redeemPack","outputs":[],"stateMutability":"payable","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":"uint256","name":"packId","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"rereleasePack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seeder","outputs":[{"internalType":"contract ISeeder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBaseCards","type":"address"}],"name":"setBaseCards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"beneficiaries","type":"address[]"},{"internalType":"uint256[]","name":"weights","type":"uint256[]"}],"name":"setBeneficiaries","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGameCards","type":"address"}],"name":"setGameCards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"packId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"setPackSaleWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"packId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setPackSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSeeder","type":"address"}],"name":"setSeeder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSigner","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"packId","type":"uint256"}],"name":"sunsetPack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"packId","type":"uint256"},{"components":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"pulls","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"purchaseLimit","type":"uint256"},{"internalType":"bool","name":"signerGated","type":"bool"},{"internalType":"uint256[]","name":"cardIds","type":"uint256[]"},{"internalType":"uint256[]","name":"cardWeights","type":"uint256[]"},{"internalType":"uint256[6]","name":"tierWeights","type":"uint256[6]"}],"internalType":"struct IETHPackShop.Pack","name":"newPack","type":"tuple"}],"name":"updatePack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405273430000000000000000000000000000000000000260805260006006553480156200002e57600080fd5b50604051620039ad380380620039ad8339810160408190526200005191620005df565b6001600160a01b03881615806200006f57506001600160a01b038716155b806200008257506001600160a01b038616155b806200009557506001600160a01b038516155b80620000a857506001600160a01b038416155b80620000bb57506001600160a01b038316155b15620000da5760405163d92e233d60e01b815260040160405180910390fd5b81511580620000ea575060058251115b156200010957604051634ec4810560e11b815260040160405180910390fd5b80518251146200012c5760405163512509d360e11b815260040160405180910390fd5b6000805b8251811015620001f857600084828151811062000151576200015162000720565b60200260200101519050600084838151811062000172576200017262000720565b6020026020010151905060006001600160a01b0316826001600160a01b031603620001b05760405163d92e233d60e01b815260040160405180910390fd5b80600003620001d25760405163585b926360e01b815260040160405180910390fd5b620001de81856200074c565b935050508080620001ef9062000768565b91505062000130565b5061271081146200021c5760405163940addc760e01b815260040160405180910390fd5b82516200023190600190602086019062000421565b508151620002479060029060208501906200048b565b506080516001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200028657600080fd5b505af11580156200029b573d6000803e3d6000fd5b5050608051604051631d70c8d360e31b81526001600160a01b038881166004830152909116925063eb8646989150602401600060405180830381600087803b158015620002e757600080fd5b505af1158015620002fc573d6000803e3d6000fd5b5050505062000311336200037960201b60201c565b6200031e896001620003b5565b5050600380546001600160a01b03199081166001600160a01b03978816179091556004805482169587169590951790945550506005805483169484169490941790935560078054909116929091169190911790555062000784565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b620003c382826001620003c7565b5050565b638b78c6d8600c52826000526020600c20805483811783620003ea575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b82805482825590600052602060002090810192821562000479579160200282015b828111156200047957825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000442565b5062000487929150620004c9565b5090565b82805482825590600052602060002090810192821562000479579160200282015b8281111562000479578251825591602001919060010190620004ac565b5b80821115620004875760008155600101620004ca565b80516001600160a01b0381168114620004f857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200053e576200053e620004fd565b604052919050565b60006001600160401b03821115620005625762000562620004fd565b5060051b60200190565b600082601f8301126200057e57600080fd5b8151602062000597620005918362000546565b62000513565b82815260059290921b84018101918181019086841115620005b757600080fd5b8286015b84811015620005d45780518352918301918301620005bb565b509695505050505050565b600080600080600080600080610100898b031215620005fd57600080fd5b6200060889620004e0565b9750602062000619818b01620004e0565b97506200062960408b01620004e0565b96506200063960608b01620004e0565b95506200064960808b01620004e0565b94506200065960a08b01620004e0565b60c08b01519094506001600160401b03808211156200067757600080fd5b818c0191508c601f8301126200068c57600080fd5b81516200069d620005918262000546565b81815260059190911b8301840190848101908f831115620006bd57600080fd5b938501935b82851015620006e657620006d685620004e0565b82529385019390850190620006c2565b60e08f015190975094505050808311156200070057600080fd5b5050620007108b828c016200056c565b9150509295985092959890939650565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111562000762576200076262000736565b92915050565b6000600182016200077d576200077d62000736565b5060010190565b60805161320d620007a060003960006105ec015261320d6000f3fe60806040526004361061023b5760003560e01c8063684931ed1161012e578063b30b161a116100ab578063eb7038111161006f578063eb703811146106db578063f04e283e146106f1578063f2fde38b14610704578063f7eb68b514610717578063fee81cf41461073757600080fd5b8063b30b161a1461062e578063b84c13921461064e578063bad956a01461067b578063c95c99531461069b578063d50b31eb146106bb57600080fd5b80638da5cb5b116100f25780638da5cb5b1461057e5780639015516a1461059757806394d0d3a6146105aa57806397d75776146105da578063b1f9c3e91461060e57600080fd5b8063684931ed146104de5780636c19e783146104fe5780637094cc221461051e578063715018a6146105565780637afb9b1d1461055e57600080fd5b806332e12cb9116101bc5780634fab5a7d116101805780634fab5a7d1461043f578063514e62fc1461045f57806351cff8d914610496578063535411ed146104b657806354d1f13d146104d657600080fd5b806332e12cb9146103b65780633351103b146103d657806335aa2c8c146103e95780634a4ee7b1146104095780634e565ada1461041c57600080fd5b80631cd64df4116102035780631cd64df4146102f3578063238ac93314610323578063256929621461035b5780632b11a147146103635780632de948071461038357600080fd5b80630297689214610240578063065dc4c11461028b5780630c40e87f146102ad578063183a4f6e146102cd5780631c10893f146102e0575b600080fd5b34801561024c57600080fd5b5061027861025b366004612786565b600860209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561029757600080fd5b506102ab6102a63660046127fc565b61076a565b005b3480156102b957600080fd5b506102ab6102c8366004612868565b610997565b6102ab6102db36600461288a565b610a38565b6102ab6102ee366004612786565b610a45565b3480156102ff57600080fd5b5061031361030e366004612786565b610a5b565b6040519015158152602001610282565b34801561032f57600080fd5b50600754610343906001600160a01b031681565b6040516001600160a01b039091168152602001610282565b6102ab610a7a565b34801561036f57600080fd5b506102ab61037e36600461288a565b610aca565b34801561038f57600080fd5b5061027861039e3660046128a3565b638b78c6d8600c908152600091909152602090205490565b3480156103c257600080fd5b506102ab6103d13660046128a3565b610d4b565b6102ab6103e4366004612907565b610de0565b3480156103f557600080fd5b506102ab610404366004612953565b61126b565b6102ab610417366004612786565b6112f8565b34801561042857600080fd5b5061043161130a565b6040516102829291906129c1565b34801561044b57600080fd5b506102ab61045a366004612a3a565b6113c7565b34801561046b57600080fd5b5061031361047a366004612786565b638b78c6d8600c90815260009290925260209091205416151590565b3480156104a257600080fd5b506102ab6104b13660046128a3565b611440565b3480156104c257600080fd5b506102ab6104d1366004612a77565b611485565b6102ab61150e565b3480156104ea57600080fd5b50600554610343906001600160a01b031681565b34801561050a57600080fd5b506102ab6105193660046128a3565b61154a565b34801561052a57600080fd5b50610278610539366004612786565b600960209081526000928352604080842090915290825290205481565b6102ab6115cf565b34801561056a57600080fd5b50600454610343906001600160a01b031681565b34801561058a57600080fd5b50638b78c6d81954610343565b6102ab6105a5366004612aa3565b6115e3565b3480156105b657600080fd5b506103136105c536600461288a565b600a6020526000908152604090205460ff1681565b3480156105e657600080fd5b506103437f000000000000000000000000000000000000000000000000000000000000000081565b34801561061a57600080fd5b506102ab6106293660046128a3565b611a60565b34801561063a57600080fd5b506102ab610649366004612b26565b611aec565b34801561065a57600080fd5b5061066e61066936600461288a565b611cba565b6040516102829190612c38565b34801561068757600080fd5b50600354610343906001600160a01b031681565b3480156106a757600080fd5b506102ab6106b6366004612868565b611e0e565b3480156106c757600080fd5b506102ab6106d63660046128a3565b611e80565b3480156106e757600080fd5b5061027860065481565b6102ab6106ff3660046128a3565b611f0c565b6102ab6107123660046128a3565b611f49565b34801561072357600080fd5b506102ab61073236600461288a565b611f70565b34801561074357600080fd5b506102786107523660046128a3565b63389a75e1600c908152600091909152602090205490565b600161077581611fe3565b8315806107825750600584115b156107a057604051634ec4810560e11b815260040160405180910390fd5b8382146107c05760405163512509d360e11b815260040160405180910390fd5b6000805b8381101561087f5760008787838181106107e0576107e0612c4b565b90506020020160208101906107f591906128a3565b9050600086868481811061080b5761080b612c4b565b60200291909101359150506001600160a01b03821661083d5760405163d92e233d60e01b815260040160405180910390fd5b8060000361085e5760405163585b926360e01b815260040160405180910390fd5b6108688185612c77565b93505050808061087790612c8a565b9150506107c4565b5061271081146108a25760405163940addc760e01b815260040160405180910390fd5b600060018054806020026020016040519081016040528092919081815260200182805480156108fa57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108dc575b5050505050905086866001919061091292919061263f565b5061091f600286866126a2565b508484604051610930929190612ca3565b60405180910390208787604051610948929190612ccc565b60405180910390208260405161095e9190612d0c565b604051908190038120907f37e9ec2010e6cd4cf7353f7d464c0ae2d4f6acd46697830082e2ab2f4169a96c90600090a450505050505050565b60016109a281611fe3565b60065483106109c45760405163887d7bd360e01b815260040160405180910390fd5b4282116109e4576040516338af65f760e01b815260040160405180910390fd5b60008381526020818152604091829020426002820155600301849055905183815284917fe56bd4f718c9731ca652339e1dbd7fad180082625179f38702ec9bddc7e37b9591015b60405180910390a2505050565b610a423382612009565b50565b610a4d612015565b610a578282612030565b5050565b638b78c6d8600c90815260008390526020902054811681145b92915050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610ad261203c565b6006548110610af45760405163887d7bd360e01b815260040160405180910390fd5b3360009081526009602090815260408083208484529091528120549003610b2e5760405163cd9911b960e01b815260040160405180910390fd5b3360009081526009602090815260408083208484529091528120805491610b5483612d4b565b9091555050600081815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e0860193909290830182828015610c0457602002820191906000526020600020905b815481526020019060010190808311610bf0575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015610c5c57602002820191906000526020600020905b815481526020019060010190808311610c48575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311610c825750505050508152505090506000610cab8261205c565b6003546101208401516040516303728ca360e01b81529293506001600160a01b03909116916303728ca391610ce7918591903390600401612d62565b600060405180830381600087803b158015610d0157600080fd5b505af1158015610d15573d6000803e3d6000fd5b50506040518592503391507fd31984102055e5db58207562982c3fec03e3f9f6f21b9681a810e6a344d5b2fe90600090a3505050565b6001610d5681611fe3565b6001600160a01b038216610d7d5760405163d92e233d60e01b815260040160405180910390fd5b600480546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fba77f4757246a5ae4182e908698755b395d9654a76ebe7623c8eba114dd7ebdf91015b60405180910390a1505050565b610de861203c565b6006548310610e0a5760405163887d7bd360e01b815260040160405180910390fd5b600083815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e0860193909290830182828015610eb557602002820191906000526020600020905b815481526020019060010190808311610ea1575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015610f0d57602002820191906000526020600020905b815481526020019060010190808311610ef9575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311610f335750505050508152505090504281604001511180610f665750428160600151105b15610f845760405163b7b2409760e01b815260040160405180910390fd5b8060800151600003610fa95760405163fe1523d160e01b815260040160405180910390fd5b80513414610fca5760405163bb201b4960e01b815260040160405180910390fd5b60a081015133600090815260086020908152604080832088845290915281208054909190610ff790612c8a565b9182905550111561101b576040516345f4131b60e01b815260040160405180910390fd5b600084815260208190526040812060040180549161103883612d4b565b91905055508060c0015115611129576040516bffffffffffffffffffffffff193360601b166020820152603481018590526000906110b5906054015b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b90506110f984848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506122369050565b6007546001600160a01b03908116911614611127576040516310c74b0360e01b815260040160405180910390fd5b505b8051156111be5760005b6001548110156111bc5760006127106002838154811061115557611155612c4b565b90600052602060002001543461116b9190612d9f565b6111759190612dcc565b90506111a9816001848154811061118e5761118e612c4b565b6000918252602090912001546001600160a01b0316906122c7565b50806111b481612c8a565b915050611133565b505b60006111c98261205c565b6003546101208401516040516303728ca360e01b81529293506001600160a01b03909116916303728ca391611205918591903390600401612d62565b600060405180830381600087803b15801561121f57600080fd5b505af1158015611233573d6000803e3d6000fd5b50506040518792503391507fc79cad949a408373456da7a9e88e8114102aa00e03a69733c70e3a0d95944ca790600090a35050505050565b600161127681611fe3565b60065483106112985760405163887d7bd360e01b815260040160405180910390fd5b6001600160a01b038416600081815260096020908152604080832087845282529182902085905590518481528592917fde24fc995852af69243801c98eb5fe76a1167501dd410219ce807f80567f7c7b910160405180910390a350505050565b611300612015565b610a578282612009565b606080600160028180548060200260200160405190810160405280929190818152602001828054801561136657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611348575b50505050509150808054806020026020016040519081016040528092919081815260200182805480156113b857602002820191906000526020600020905b8154815260200190600101908083116113a4575b50505050509050915091509091565b60016113d281611fe3565b6113db826122e3565b60068054600091826113ec83612c8a565b909155506000818152602081905260409020909150839061140d8282612f16565b905050807f41b180bf49556910c69d55efe5a7f3391a7f277afe44f791b92b6bd06db53a5284604051610a2b9190613100565b600161144b81611fe3565b6001600160a01b0382166114725760405163d92e233d60e01b815260040160405180910390fd5b610a576001600160a01b038316476122c7565b600161149081611fe3565b60065484106114b25760405163887d7bd360e01b815260040160405180910390fd5b6000848152602081815260409182902060028101869055600301849055815185815290810184905285917f3858b7d3ea22bf301571d36fd648d013c95a8ff1daffca207cb37edcc93e6cc591015b60405180910390a250505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b600161155581611fe3565b6001600160a01b03821661157c5760405163d92e233d60e01b815260040160405180910390fd5b600780546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb90600090a3505050565b6115d7612015565b6115e160006125a8565b565b6115eb61203c565b600654861061160d5760405163887d7bd360e01b815260040160405180910390fd5b6000858152600a602052604090205460ff161561163d57604051631f6d5aef60e01b815260040160405180910390fd5b6000858152600a60209081526040808320805460ff1916600117905551611672916110749133918b918b918b918b9101613113565b600754604080516020601f87018190048102820181019092528581529293506001600160a01b03909116916116c491869086908190840183828082843760009201919091525086939250506122369050565b6001600160a01b0316146116eb576040516310c74b0360e01b815260040160405180910390fd5b600087815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e086019390929083018282801561179657602002820191906000526020600020905b815481526020019060010190808311611782575b50505050508152602001600882018054806020026020016040519081016040528092919081815260200182805480156117ee57602002820191906000526020600020905b8154815260200190600101908083116117da575b50505091835250506040805160c081019182905260209092019190600984019060069082845b81548152602001906001019080831161181457505050505081525050905042816040015111806118475750428160600151105b156118655760405163b7b2409760e01b815260040160405180910390fd5b806080015160000361188a5760405163fe1523d160e01b815260040160405180910390fd5b805134146118ab5760405163bb201b4960e01b815260040160405180910390fd5b60a08101513360009081526008602090815260408083208c8452909152812080549091906118d890612c8a565b918290555011156118fc576040516345f4131b60e01b815260040160405180910390fd5b600088815260208190526040812060040180549161191983612d4b565b90915550508051156119985760005b6001548110156119965760006127106002838154811061194a5761194a612c4b565b9060005260206000200154346119609190612d9f565b61196a9190612dcc565b9050611983816001848154811061118e5761118e612c4b565b508061198e81612c8a565b915050611928565b505b60006119a38261205c565b6003546101208401516040516303728ca360e01b81529293506001600160a01b03909116916303728ca3916119df918591903390600401612d62565b600060405180830381600087803b1580156119f957600080fd5b505af1158015611a0d573d6000803e3d6000fd5b5050505088336001600160a01b03167fa2c40a4aba7f37a65a8fbdd53e54bfc58b74a505cf519e34b22b2cf536b4a1678989604051611a4d92919061314d565b60405180910390a3505050505050505050565b6001611a6b81611fe3565b6001600160a01b038216611a925760405163d92e233d60e01b815260040160405180910390fd5b600380546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fe9795c906da19cb7144768780013cf1fd82c50d976dd18d881e87c31e05311d89101610dd3565b6001611af781611fe3565b6006548310611b195760405163887d7bd360e01b815260040160405180910390fd5b611b22826122e3565b600083815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e0860193909290830182828015611bcd57602002820191906000526020600020905b815481526020019060010190808311611bb9575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015611c2557602002820191906000526020600020905b815481526020019060010190808311611c11575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311611c4b575050509190925250505060008581526020819052604090209091508390611c858282612f16565b905050837f68513b82f07d643a04872897aad2d929ddfc8e0aa7e144c55604ca33b44c25d9828560405161150092919061317c565b611cc26126dd565b60008281526020818152604091829020825161014081018452815481526001820154818401526002820154818501526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548551818602810186019096528086529194929360e08601939290830182828015611d6d57602002820191906000526020600020905b815481526020019060010190808311611d59575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015611dc557602002820191906000526020600020905b815481526020019060010190808311611db1575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311611deb575050505050815250509050919050565b6001611e1981611fe3565b6006548310611e3b5760405163887d7bd360e01b815260040160405180910390fd5b60008381526020818152604091829020600401849055905183815284917f0bf8b7e6a0a757060ee7f7b1d773dc42e0cd9107a92c5e43e18ef75383aa7c4c9101610a2b565b6001611e8b81611fe3565b6001600160a01b038216611eb25760405163d92e233d60e01b815260040160405180910390fd5b600580546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fe6a0768bc7cc02a7502c4e06cdb639aca06180fd05c4e57dddea1b2d1b0e8c0b9101610dd3565b611f14612015565b63389a75e1600c52806000526020600c208054421115611f3c57636f5e88186000526004601cfd5b60009055610a42816125a8565b611f51612015565b8060601b611f6757637448fbae6000526004601cfd5b610a42816125a8565b6001611f7b81611fe3565b6006548210611f9d5760405163887d7bd360e01b815260040160405180910390fd5b600082815260208190526040808220600281018390556003018290555183917f1ac60eb99f03b3101fd06d357753fe2cc8b9f675ce29a1d32911ed29acf26a6191a25050565b638b78c6d8600c5233600052806020600c205416610a42576382b429006000526004601cfd5b610a57828260006125e6565b638b78c6d8195433146115e1576382b429006000526004601cfd5b610a57828260016125e6565b3332146115e15760405163e02c6ccf60e01b815260040160405180910390fd5b60606000826020015167ffffffffffffffff81111561207d5761207d612e45565b6040519080825280602002602001820160405280156120a6578160200160208202803683370190505b5090506000600560009054906101000a90046001600160a01b03166001600160a01b031663055877756040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612100573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212491906131aa565b905060005b846020015181101561222d576000612143612710846131c3565b61214e906001612c77565b90506000805b876101000151518110156121e857876101000151818151811061217957612179612c4b565b60200260200101518261218c9190612c77565b91508183116121d6578760e0015181815181106121ab576121ab612c4b565b60200260200101518685815181106121c5576121c5612c4b565b6020026020010181815250506121e8565b806121e081612c8a565b915050612154565b5060408051602081018690529081018490526060016040516020818303038152906040528051906020012060001c93505050808061222590612c8a565b915050612129565b50909392505050565b604051600190836000526020830151604052604083510361227257604083015160ff81901c601b016020526001600160ff1b0316606052612298565b604183510361229357606083015160001a6020526040830151606052612298565b600091505b6020600160806000855afa5191503d6122b957638baa579f6000526004601cfd5b600060605260405292915050565b60003860003884865af1610a575763b12d13eb6000526004601cfd5b6122f1610100820182612dfb565b905061230060e0830183612dfb565b9050146123205760405163512509d360e11b815260040160405180910390fd5b61232d60e0820182612dfb565b905060000361234f57604051630f59b9ff60e01b815260040160405180910390fd5b806020013560000361237457604051632facb9b960e21b815260040160405180910390fd5b806060013581604001351061239c57604051632f4bb82160e11b815260040160405180910390fd5b80608001356000036123c157604051632a49433960e11b815260040160405180910390fd5b8060a001356000036123e657604051634cdbe66f60e01b815260040160405180910390fd5b6000600460009054906101000a90046001600160a01b03166001600160a01b031663c3702fa76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561243b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245f91906131aa565b90506000805b612473610100850185612dfb565b90508110156125155761248a610100850185612dfb565b8281811061249a5761249a612c4b565b90506020020135826124ac9190612c77565b915060006124bd60e0860186612dfb565b838181106124cd576124cd612c4b565b90506020020135905080600014806124e457508381115b1561250257604051630352a4a760e21b815260040160405180910390fd5b508061250d81612c8a565b915050612465565b50612710811461253857604051630f12576960e41b815260040160405180910390fd5b506000805b6006811015612580578361012001816006811061255c5761255c612c4b565b60200201358261256c9190612c77565b91508061257881612c8a565b91505061253d565b5061271081146125a35760405163940addc760e01b815260040160405180910390fd5b505050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b638b78c6d8600c52826000526020600c20805483811783612608575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b828054828255906000526020600020908101928215612692579160200282015b828111156126925781546001600160a01b0319166001600160a01b0384351617825560209092019160019091019061265f565b5061269e929150612737565b5090565b828054828255906000526020600020908101928215612692579160200282015b828111156126925782358255916020019190600101906126c2565b604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001606081526020016060815260200161273261274c565b905290565b5b8082111561269e5760008155600101612738565b6040518060c001604052806006906020820280368337509192915050565b80356001600160a01b038116811461278157600080fd5b919050565b6000806040838503121561279957600080fd5b6127a28361276a565b946020939093013593505050565b60008083601f8401126127c257600080fd5b50813567ffffffffffffffff8111156127da57600080fd5b6020830191508360208260051b85010111156127f557600080fd5b9250929050565b6000806000806040858703121561281257600080fd5b843567ffffffffffffffff8082111561282a57600080fd5b612836888389016127b0565b9096509450602087013591508082111561284f57600080fd5b5061285c878288016127b0565b95989497509550505050565b6000806040838503121561287b57600080fd5b50508035926020909101359150565b60006020828403121561289c57600080fd5b5035919050565b6000602082840312156128b557600080fd5b6128be8261276a565b9392505050565b60008083601f8401126128d757600080fd5b50813567ffffffffffffffff8111156128ef57600080fd5b6020830191508360208285010111156127f557600080fd5b60008060006040848603121561291c57600080fd5b83359250602084013567ffffffffffffffff81111561293a57600080fd5b612946868287016128c5565b9497909650939450505050565b60008060006060848603121561296857600080fd5b6129718461276a565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b838110156129b65781518752958201959082019060010161299a565b509495945050505050565b604080825283519082018190526000906020906060840190828701845b82811015612a035781516001600160a01b0316845292840192908401906001016129de565b50505083810382850152612a178186612986565b9695505050505050565b60006101e08284031215612a3457600080fd5b50919050565b600060208284031215612a4c57600080fd5b813567ffffffffffffffff811115612a6357600080fd5b612a6f84828501612a21565b949350505050565b600080600060608486031215612a8c57600080fd5b505081359360208301359350604090920135919050565b60008060008060008060808789031215612abc57600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115612ae257600080fd5b612aee8a838b016128c5565b90965094506060890135915080821115612b0757600080fd5b50612b1489828a016128c5565b979a9699509497509295939492505050565b60008060408385031215612b3957600080fd5b82359150602083013567ffffffffffffffff811115612b5757600080fd5b612b6385828601612a21565b9150509250929050565b8060005b6006811015612b90578151845260209384019390910190600101612b71565b50505050565b60006101e0825184526020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c0830151612be460c086018215159052565b5060e08301518160e0860152612bfc82860182612986565b9150506101008084015185830382870152612c178382612986565b9250505061012080840151612c2e82870182612b6d565b5090949350505050565b6020815260006128be6020830184612b96565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610a7457610a74612c61565b600060018201612c9c57612c9c612c61565b5060010190565b60006001600160fb1b03831115612cb957600080fd5b8260051b80858437919091019392505050565b60008184825b85811015612d01576001600160a01b03612ceb8361276a565b1683526020928301929190910190600101612cd2565b509095945050505050565b815160009082906020808601845b83811015612d3f5781516001600160a01b031685529382019390820190600101612d1a565b50929695505050505050565b600081612d5a57612d5a612c61565b506000190190565b6000610100808352612d7681840187612986565b915050612d866020830185612b6d565b6001600160a01b039290921660e0919091015292915050565b8082028115828204841417610a7457610a74612c61565b634e487b7160e01b600052601260045260246000fd5b600082612ddb57612ddb612db6565b500490565b8015158114610a4257600080fd5b60008135610a7481612de0565b6000808335601e19843603018112612e1257600080fd5b83018035915067ffffffffffffffff821115612e2d57600080fd5b6020019150600581901b36038213156127f557600080fd5b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff831115612e7357612e73612e45565b68010000000000000000831115612e8c57612e8c612e45565b805483825580841015612ec3576000828152602081208581019083015b80821015612ebf57828255600182019150612ea9565b5050505b50818160005260208060002060005b86811015612eec5783358282015592820192600101612ed2565b50505050505050565b8160005b6006811015612b9057813583820155602090910190600101612ef9565b813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a08201356005820155612f74612f5b60c08401612dee565b6006830160ff1981541660ff8315151681178255505050565b612f8160e0830183612dfb565b612f8f818360078601612e5b565b5050612f9f610100830183612dfb565b612fad818360088601612e5b565b5050610a57610120830160098301612ef5565b803561278181612de0565b6000808335601e19843603018112612fe257600080fd5b830160208101925035905067ffffffffffffffff81111561300257600080fd5b8060051b36038213156127f557600080fd5b81835260006001600160fb1b0383111561302d57600080fd5b8260051b80836020870137939093016020019392505050565b60c08183375050565b60006101e0823584526020830135602085015260408301356040850152606083013560608501526080830135608085015260a083013560a085015261309660c08401612fc0565b151560c08501526130aa60e0840184612fcb565b8260e08701526130bd8387018284613014565b925050506101006130d081850185612fcb565b868403838801526130e2848284613014565b93505050506101206130f8818601828601613046565b509392505050565b6020815260006128be602083018461304f565b6bffffffffffffffffffffffff198660601b1681528460148201528360348201528183605483013760009101605401908152949350505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60408152600061318f6040830185612b96565b82810360208401526131a1818561304f565b95945050505050565b6000602082840312156131bc57600080fd5b5051919050565b6000826131d2576131d2612db6565b50069056fea264697066735822122000e62efa67ff3ab48451d3f0c518790efd64cd482589503fd2c7612d3ed4f44764736f6c6343000814003300000000000000000000000051a16e6aec2924e8886fc323618876e3ed0e4de50000000000000000000000004131ae1e157c91fe083bdcf857a230fb79ac903a00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a8000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac10000000000000000000000001facd50481d827d7d342d79278b9c5a1f9eb6cd7000000000000000000000000abb8621b2f4fb61f083b9f2a033a40086db9030d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000020000000000000000000000006b15b2220973ad753c4f52c2ef748870288f31b100000000000000000000000042398533272ed19ad79bdc32355c530827f08f9f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000013880000000000000000000000000000000000000000000000000000000000001388
Deployed Bytecode
0x60806040526004361061023b5760003560e01c8063684931ed1161012e578063b30b161a116100ab578063eb7038111161006f578063eb703811146106db578063f04e283e146106f1578063f2fde38b14610704578063f7eb68b514610717578063fee81cf41461073757600080fd5b8063b30b161a1461062e578063b84c13921461064e578063bad956a01461067b578063c95c99531461069b578063d50b31eb146106bb57600080fd5b80638da5cb5b116100f25780638da5cb5b1461057e5780639015516a1461059757806394d0d3a6146105aa57806397d75776146105da578063b1f9c3e91461060e57600080fd5b8063684931ed146104de5780636c19e783146104fe5780637094cc221461051e578063715018a6146105565780637afb9b1d1461055e57600080fd5b806332e12cb9116101bc5780634fab5a7d116101805780634fab5a7d1461043f578063514e62fc1461045f57806351cff8d914610496578063535411ed146104b657806354d1f13d146104d657600080fd5b806332e12cb9146103b65780633351103b146103d657806335aa2c8c146103e95780634a4ee7b1146104095780634e565ada1461041c57600080fd5b80631cd64df4116102035780631cd64df4146102f3578063238ac93314610323578063256929621461035b5780632b11a147146103635780632de948071461038357600080fd5b80630297689214610240578063065dc4c11461028b5780630c40e87f146102ad578063183a4f6e146102cd5780631c10893f146102e0575b600080fd5b34801561024c57600080fd5b5061027861025b366004612786565b600860209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561029757600080fd5b506102ab6102a63660046127fc565b61076a565b005b3480156102b957600080fd5b506102ab6102c8366004612868565b610997565b6102ab6102db36600461288a565b610a38565b6102ab6102ee366004612786565b610a45565b3480156102ff57600080fd5b5061031361030e366004612786565b610a5b565b6040519015158152602001610282565b34801561032f57600080fd5b50600754610343906001600160a01b031681565b6040516001600160a01b039091168152602001610282565b6102ab610a7a565b34801561036f57600080fd5b506102ab61037e36600461288a565b610aca565b34801561038f57600080fd5b5061027861039e3660046128a3565b638b78c6d8600c908152600091909152602090205490565b3480156103c257600080fd5b506102ab6103d13660046128a3565b610d4b565b6102ab6103e4366004612907565b610de0565b3480156103f557600080fd5b506102ab610404366004612953565b61126b565b6102ab610417366004612786565b6112f8565b34801561042857600080fd5b5061043161130a565b6040516102829291906129c1565b34801561044b57600080fd5b506102ab61045a366004612a3a565b6113c7565b34801561046b57600080fd5b5061031361047a366004612786565b638b78c6d8600c90815260009290925260209091205416151590565b3480156104a257600080fd5b506102ab6104b13660046128a3565b611440565b3480156104c257600080fd5b506102ab6104d1366004612a77565b611485565b6102ab61150e565b3480156104ea57600080fd5b50600554610343906001600160a01b031681565b34801561050a57600080fd5b506102ab6105193660046128a3565b61154a565b34801561052a57600080fd5b50610278610539366004612786565b600960209081526000928352604080842090915290825290205481565b6102ab6115cf565b34801561056a57600080fd5b50600454610343906001600160a01b031681565b34801561058a57600080fd5b50638b78c6d81954610343565b6102ab6105a5366004612aa3565b6115e3565b3480156105b657600080fd5b506103136105c536600461288a565b600a6020526000908152604090205460ff1681565b3480156105e657600080fd5b506103437f000000000000000000000000430000000000000000000000000000000000000281565b34801561061a57600080fd5b506102ab6106293660046128a3565b611a60565b34801561063a57600080fd5b506102ab610649366004612b26565b611aec565b34801561065a57600080fd5b5061066e61066936600461288a565b611cba565b6040516102829190612c38565b34801561068757600080fd5b50600354610343906001600160a01b031681565b3480156106a757600080fd5b506102ab6106b6366004612868565b611e0e565b3480156106c757600080fd5b506102ab6106d63660046128a3565b611e80565b3480156106e757600080fd5b5061027860065481565b6102ab6106ff3660046128a3565b611f0c565b6102ab6107123660046128a3565b611f49565b34801561072357600080fd5b506102ab61073236600461288a565b611f70565b34801561074357600080fd5b506102786107523660046128a3565b63389a75e1600c908152600091909152602090205490565b600161077581611fe3565b8315806107825750600584115b156107a057604051634ec4810560e11b815260040160405180910390fd5b8382146107c05760405163512509d360e11b815260040160405180910390fd5b6000805b8381101561087f5760008787838181106107e0576107e0612c4b565b90506020020160208101906107f591906128a3565b9050600086868481811061080b5761080b612c4b565b60200291909101359150506001600160a01b03821661083d5760405163d92e233d60e01b815260040160405180910390fd5b8060000361085e5760405163585b926360e01b815260040160405180910390fd5b6108688185612c77565b93505050808061087790612c8a565b9150506107c4565b5061271081146108a25760405163940addc760e01b815260040160405180910390fd5b600060018054806020026020016040519081016040528092919081815260200182805480156108fa57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108dc575b5050505050905086866001919061091292919061263f565b5061091f600286866126a2565b508484604051610930929190612ca3565b60405180910390208787604051610948929190612ccc565b60405180910390208260405161095e9190612d0c565b604051908190038120907f37e9ec2010e6cd4cf7353f7d464c0ae2d4f6acd46697830082e2ab2f4169a96c90600090a450505050505050565b60016109a281611fe3565b60065483106109c45760405163887d7bd360e01b815260040160405180910390fd5b4282116109e4576040516338af65f760e01b815260040160405180910390fd5b60008381526020818152604091829020426002820155600301849055905183815284917fe56bd4f718c9731ca652339e1dbd7fad180082625179f38702ec9bddc7e37b9591015b60405180910390a2505050565b610a423382612009565b50565b610a4d612015565b610a578282612030565b5050565b638b78c6d8600c90815260008390526020902054811681145b92915050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610ad261203c565b6006548110610af45760405163887d7bd360e01b815260040160405180910390fd5b3360009081526009602090815260408083208484529091528120549003610b2e5760405163cd9911b960e01b815260040160405180910390fd5b3360009081526009602090815260408083208484529091528120805491610b5483612d4b565b9091555050600081815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e0860193909290830182828015610c0457602002820191906000526020600020905b815481526020019060010190808311610bf0575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015610c5c57602002820191906000526020600020905b815481526020019060010190808311610c48575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311610c825750505050508152505090506000610cab8261205c565b6003546101208401516040516303728ca360e01b81529293506001600160a01b03909116916303728ca391610ce7918591903390600401612d62565b600060405180830381600087803b158015610d0157600080fd5b505af1158015610d15573d6000803e3d6000fd5b50506040518592503391507fd31984102055e5db58207562982c3fec03e3f9f6f21b9681a810e6a344d5b2fe90600090a3505050565b6001610d5681611fe3565b6001600160a01b038216610d7d5760405163d92e233d60e01b815260040160405180910390fd5b600480546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fba77f4757246a5ae4182e908698755b395d9654a76ebe7623c8eba114dd7ebdf91015b60405180910390a1505050565b610de861203c565b6006548310610e0a5760405163887d7bd360e01b815260040160405180910390fd5b600083815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e0860193909290830182828015610eb557602002820191906000526020600020905b815481526020019060010190808311610ea1575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015610f0d57602002820191906000526020600020905b815481526020019060010190808311610ef9575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311610f335750505050508152505090504281604001511180610f665750428160600151105b15610f845760405163b7b2409760e01b815260040160405180910390fd5b8060800151600003610fa95760405163fe1523d160e01b815260040160405180910390fd5b80513414610fca5760405163bb201b4960e01b815260040160405180910390fd5b60a081015133600090815260086020908152604080832088845290915281208054909190610ff790612c8a565b9182905550111561101b576040516345f4131b60e01b815260040160405180910390fd5b600084815260208190526040812060040180549161103883612d4b565b91905055508060c0015115611129576040516bffffffffffffffffffffffff193360601b166020820152603481018590526000906110b5906054015b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b90506110f984848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085939250506122369050565b6007546001600160a01b03908116911614611127576040516310c74b0360e01b815260040160405180910390fd5b505b8051156111be5760005b6001548110156111bc5760006127106002838154811061115557611155612c4b565b90600052602060002001543461116b9190612d9f565b6111759190612dcc565b90506111a9816001848154811061118e5761118e612c4b565b6000918252602090912001546001600160a01b0316906122c7565b50806111b481612c8a565b915050611133565b505b60006111c98261205c565b6003546101208401516040516303728ca360e01b81529293506001600160a01b03909116916303728ca391611205918591903390600401612d62565b600060405180830381600087803b15801561121f57600080fd5b505af1158015611233573d6000803e3d6000fd5b50506040518792503391507fc79cad949a408373456da7a9e88e8114102aa00e03a69733c70e3a0d95944ca790600090a35050505050565b600161127681611fe3565b60065483106112985760405163887d7bd360e01b815260040160405180910390fd5b6001600160a01b038416600081815260096020908152604080832087845282529182902085905590518481528592917fde24fc995852af69243801c98eb5fe76a1167501dd410219ce807f80567f7c7b910160405180910390a350505050565b611300612015565b610a578282612009565b606080600160028180548060200260200160405190810160405280929190818152602001828054801561136657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611348575b50505050509150808054806020026020016040519081016040528092919081815260200182805480156113b857602002820191906000526020600020905b8154815260200190600101908083116113a4575b50505050509050915091509091565b60016113d281611fe3565b6113db826122e3565b60068054600091826113ec83612c8a565b909155506000818152602081905260409020909150839061140d8282612f16565b905050807f41b180bf49556910c69d55efe5a7f3391a7f277afe44f791b92b6bd06db53a5284604051610a2b9190613100565b600161144b81611fe3565b6001600160a01b0382166114725760405163d92e233d60e01b815260040160405180910390fd5b610a576001600160a01b038316476122c7565b600161149081611fe3565b60065484106114b25760405163887d7bd360e01b815260040160405180910390fd5b6000848152602081815260409182902060028101869055600301849055815185815290810184905285917f3858b7d3ea22bf301571d36fd648d013c95a8ff1daffca207cb37edcc93e6cc591015b60405180910390a250505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b600161155581611fe3565b6001600160a01b03821661157c5760405163d92e233d60e01b815260040160405180910390fd5b600780546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb90600090a3505050565b6115d7612015565b6115e160006125a8565b565b6115eb61203c565b600654861061160d5760405163887d7bd360e01b815260040160405180910390fd5b6000858152600a602052604090205460ff161561163d57604051631f6d5aef60e01b815260040160405180910390fd5b6000858152600a60209081526040808320805460ff1916600117905551611672916110749133918b918b918b918b9101613113565b600754604080516020601f87018190048102820181019092528581529293506001600160a01b03909116916116c491869086908190840183828082843760009201919091525086939250506122369050565b6001600160a01b0316146116eb576040516310c74b0360e01b815260040160405180910390fd5b600087815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e086019390929083018282801561179657602002820191906000526020600020905b815481526020019060010190808311611782575b50505050508152602001600882018054806020026020016040519081016040528092919081815260200182805480156117ee57602002820191906000526020600020905b8154815260200190600101908083116117da575b50505091835250506040805160c081019182905260209092019190600984019060069082845b81548152602001906001019080831161181457505050505081525050905042816040015111806118475750428160600151105b156118655760405163b7b2409760e01b815260040160405180910390fd5b806080015160000361188a5760405163fe1523d160e01b815260040160405180910390fd5b805134146118ab5760405163bb201b4960e01b815260040160405180910390fd5b60a08101513360009081526008602090815260408083208c8452909152812080549091906118d890612c8a565b918290555011156118fc576040516345f4131b60e01b815260040160405180910390fd5b600088815260208190526040812060040180549161191983612d4b565b90915550508051156119985760005b6001548110156119965760006127106002838154811061194a5761194a612c4b565b9060005260206000200154346119609190612d9f565b61196a9190612dcc565b9050611983816001848154811061118e5761118e612c4b565b508061198e81612c8a565b915050611928565b505b60006119a38261205c565b6003546101208401516040516303728ca360e01b81529293506001600160a01b03909116916303728ca3916119df918591903390600401612d62565b600060405180830381600087803b1580156119f957600080fd5b505af1158015611a0d573d6000803e3d6000fd5b5050505088336001600160a01b03167fa2c40a4aba7f37a65a8fbdd53e54bfc58b74a505cf519e34b22b2cf536b4a1678989604051611a4d92919061314d565b60405180910390a3505050505050505050565b6001611a6b81611fe3565b6001600160a01b038216611a925760405163d92e233d60e01b815260040160405180910390fd5b600380546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fe9795c906da19cb7144768780013cf1fd82c50d976dd18d881e87c31e05311d89101610dd3565b6001611af781611fe3565b6006548310611b195760405163887d7bd360e01b815260040160405180910390fd5b611b22826122e3565b600083815260208181526040808320815161014081018352815481526001820154818501526002820154818401526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548451818702810187019095528085529194929360e0860193909290830182828015611bcd57602002820191906000526020600020905b815481526020019060010190808311611bb9575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015611c2557602002820191906000526020600020905b815481526020019060010190808311611c11575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311611c4b575050509190925250505060008581526020819052604090209091508390611c858282612f16565b905050837f68513b82f07d643a04872897aad2d929ddfc8e0aa7e144c55604ca33b44c25d9828560405161150092919061317c565b611cc26126dd565b60008281526020818152604091829020825161014081018452815481526001820154818401526002820154818501526003820154606082015260048201546080820152600582015460a0820152600682015460ff16151560c08201526007820180548551818602810186019096528086529194929360e08601939290830182828015611d6d57602002820191906000526020600020905b815481526020019060010190808311611d59575b5050505050815260200160088201805480602002602001604051908101604052809291908181526020018280548015611dc557602002820191906000526020600020905b815481526020019060010190808311611db1575b50505091835250506040805160c081019182905260209092019190600984019060069082845b815481526020019060010190808311611deb575050505050815250509050919050565b6001611e1981611fe3565b6006548310611e3b5760405163887d7bd360e01b815260040160405180910390fd5b60008381526020818152604091829020600401849055905183815284917f0bf8b7e6a0a757060ee7f7b1d773dc42e0cd9107a92c5e43e18ef75383aa7c4c9101610a2b565b6001611e8b81611fe3565b6001600160a01b038216611eb25760405163d92e233d60e01b815260040160405180910390fd5b600580546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fe6a0768bc7cc02a7502c4e06cdb639aca06180fd05c4e57dddea1b2d1b0e8c0b9101610dd3565b611f14612015565b63389a75e1600c52806000526020600c208054421115611f3c57636f5e88186000526004601cfd5b60009055610a42816125a8565b611f51612015565b8060601b611f6757637448fbae6000526004601cfd5b610a42816125a8565b6001611f7b81611fe3565b6006548210611f9d5760405163887d7bd360e01b815260040160405180910390fd5b600082815260208190526040808220600281018390556003018290555183917f1ac60eb99f03b3101fd06d357753fe2cc8b9f675ce29a1d32911ed29acf26a6191a25050565b638b78c6d8600c5233600052806020600c205416610a42576382b429006000526004601cfd5b610a57828260006125e6565b638b78c6d8195433146115e1576382b429006000526004601cfd5b610a57828260016125e6565b3332146115e15760405163e02c6ccf60e01b815260040160405180910390fd5b60606000826020015167ffffffffffffffff81111561207d5761207d612e45565b6040519080825280602002602001820160405280156120a6578160200160208202803683370190505b5090506000600560009054906101000a90046001600160a01b03166001600160a01b031663055877756040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612100573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212491906131aa565b905060005b846020015181101561222d576000612143612710846131c3565b61214e906001612c77565b90506000805b876101000151518110156121e857876101000151818151811061217957612179612c4b565b60200260200101518261218c9190612c77565b91508183116121d6578760e0015181815181106121ab576121ab612c4b565b60200260200101518685815181106121c5576121c5612c4b565b6020026020010181815250506121e8565b806121e081612c8a565b915050612154565b5060408051602081018690529081018490526060016040516020818303038152906040528051906020012060001c93505050808061222590612c8a565b915050612129565b50909392505050565b604051600190836000526020830151604052604083510361227257604083015160ff81901c601b016020526001600160ff1b0316606052612298565b604183510361229357606083015160001a6020526040830151606052612298565b600091505b6020600160806000855afa5191503d6122b957638baa579f6000526004601cfd5b600060605260405292915050565b60003860003884865af1610a575763b12d13eb6000526004601cfd5b6122f1610100820182612dfb565b905061230060e0830183612dfb565b9050146123205760405163512509d360e11b815260040160405180910390fd5b61232d60e0820182612dfb565b905060000361234f57604051630f59b9ff60e01b815260040160405180910390fd5b806020013560000361237457604051632facb9b960e21b815260040160405180910390fd5b806060013581604001351061239c57604051632f4bb82160e11b815260040160405180910390fd5b80608001356000036123c157604051632a49433960e11b815260040160405180910390fd5b8060a001356000036123e657604051634cdbe66f60e01b815260040160405180910390fd5b6000600460009054906101000a90046001600160a01b03166001600160a01b031663c3702fa76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561243b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245f91906131aa565b90506000805b612473610100850185612dfb565b90508110156125155761248a610100850185612dfb565b8281811061249a5761249a612c4b565b90506020020135826124ac9190612c77565b915060006124bd60e0860186612dfb565b838181106124cd576124cd612c4b565b90506020020135905080600014806124e457508381115b1561250257604051630352a4a760e21b815260040160405180910390fd5b508061250d81612c8a565b915050612465565b50612710811461253857604051630f12576960e41b815260040160405180910390fd5b506000805b6006811015612580578361012001816006811061255c5761255c612c4b565b60200201358261256c9190612c77565b91508061257881612c8a565b91505061253d565b5061271081146125a35760405163940addc760e01b815260040160405180910390fd5b505050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b638b78c6d8600c52826000526020600c20805483811783612608575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a3505050505050565b828054828255906000526020600020908101928215612692579160200282015b828111156126925781546001600160a01b0319166001600160a01b0384351617825560209092019160019091019061265f565b5061269e929150612737565b5090565b828054828255906000526020600020908101928215612692579160200282015b828111156126925782358255916020019190600101906126c2565b604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001606081526020016060815260200161273261274c565b905290565b5b8082111561269e5760008155600101612738565b6040518060c001604052806006906020820280368337509192915050565b80356001600160a01b038116811461278157600080fd5b919050565b6000806040838503121561279957600080fd5b6127a28361276a565b946020939093013593505050565b60008083601f8401126127c257600080fd5b50813567ffffffffffffffff8111156127da57600080fd5b6020830191508360208260051b85010111156127f557600080fd5b9250929050565b6000806000806040858703121561281257600080fd5b843567ffffffffffffffff8082111561282a57600080fd5b612836888389016127b0565b9096509450602087013591508082111561284f57600080fd5b5061285c878288016127b0565b95989497509550505050565b6000806040838503121561287b57600080fd5b50508035926020909101359150565b60006020828403121561289c57600080fd5b5035919050565b6000602082840312156128b557600080fd5b6128be8261276a565b9392505050565b60008083601f8401126128d757600080fd5b50813567ffffffffffffffff8111156128ef57600080fd5b6020830191508360208285010111156127f557600080fd5b60008060006040848603121561291c57600080fd5b83359250602084013567ffffffffffffffff81111561293a57600080fd5b612946868287016128c5565b9497909650939450505050565b60008060006060848603121561296857600080fd5b6129718461276a565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b838110156129b65781518752958201959082019060010161299a565b509495945050505050565b604080825283519082018190526000906020906060840190828701845b82811015612a035781516001600160a01b0316845292840192908401906001016129de565b50505083810382850152612a178186612986565b9695505050505050565b60006101e08284031215612a3457600080fd5b50919050565b600060208284031215612a4c57600080fd5b813567ffffffffffffffff811115612a6357600080fd5b612a6f84828501612a21565b949350505050565b600080600060608486031215612a8c57600080fd5b505081359360208301359350604090920135919050565b60008060008060008060808789031215612abc57600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115612ae257600080fd5b612aee8a838b016128c5565b90965094506060890135915080821115612b0757600080fd5b50612b1489828a016128c5565b979a9699509497509295939492505050565b60008060408385031215612b3957600080fd5b82359150602083013567ffffffffffffffff811115612b5757600080fd5b612b6385828601612a21565b9150509250929050565b8060005b6006811015612b90578151845260209384019390910190600101612b71565b50505050565b60006101e0825184526020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c0830151612be460c086018215159052565b5060e08301518160e0860152612bfc82860182612986565b9150506101008084015185830382870152612c178382612986565b9250505061012080840151612c2e82870182612b6d565b5090949350505050565b6020815260006128be6020830184612b96565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610a7457610a74612c61565b600060018201612c9c57612c9c612c61565b5060010190565b60006001600160fb1b03831115612cb957600080fd5b8260051b80858437919091019392505050565b60008184825b85811015612d01576001600160a01b03612ceb8361276a565b1683526020928301929190910190600101612cd2565b509095945050505050565b815160009082906020808601845b83811015612d3f5781516001600160a01b031685529382019390820190600101612d1a565b50929695505050505050565b600081612d5a57612d5a612c61565b506000190190565b6000610100808352612d7681840187612986565b915050612d866020830185612b6d565b6001600160a01b039290921660e0919091015292915050565b8082028115828204841417610a7457610a74612c61565b634e487b7160e01b600052601260045260246000fd5b600082612ddb57612ddb612db6565b500490565b8015158114610a4257600080fd5b60008135610a7481612de0565b6000808335601e19843603018112612e1257600080fd5b83018035915067ffffffffffffffff821115612e2d57600080fd5b6020019150600581901b36038213156127f557600080fd5b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff831115612e7357612e73612e45565b68010000000000000000831115612e8c57612e8c612e45565b805483825580841015612ec3576000828152602081208581019083015b80821015612ebf57828255600182019150612ea9565b5050505b50818160005260208060002060005b86811015612eec5783358282015592820192600101612ed2565b50505050505050565b8160005b6006811015612b9057813583820155602090910190600101612ef9565b813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a08201356005820155612f74612f5b60c08401612dee565b6006830160ff1981541660ff8315151681178255505050565b612f8160e0830183612dfb565b612f8f818360078601612e5b565b5050612f9f610100830183612dfb565b612fad818360088601612e5b565b5050610a57610120830160098301612ef5565b803561278181612de0565b6000808335601e19843603018112612fe257600080fd5b830160208101925035905067ffffffffffffffff81111561300257600080fd5b8060051b36038213156127f557600080fd5b81835260006001600160fb1b0383111561302d57600080fd5b8260051b80836020870137939093016020019392505050565b60c08183375050565b60006101e0823584526020830135602085015260408301356040850152606083013560608501526080830135608085015260a083013560a085015261309660c08401612fc0565b151560c08501526130aa60e0840184612fcb565b8260e08701526130bd8387018284613014565b925050506101006130d081850185612fcb565b868403838801526130e2848284613014565b93505050506101206130f8818601828601613046565b509392505050565b6020815260006128be602083018461304f565b6bffffffffffffffffffffffff198660601b1681528460148201528360348201528183605483013760009101605401908152949350505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60408152600061318f6040830185612b96565b82810360208401526131a1818561304f565b95945050505050565b6000602082840312156131bc57600080fd5b5051919050565b6000826131d2576131d2612db6565b50069056fea264697066735822122000e62efa67ff3ab48451d3f0c518790efd64cd482589503fd2c7612d3ed4f44764736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000051a16e6aec2924e8886fc323618876e3ed0e4de50000000000000000000000004131ae1e157c91fe083bdcf857a230fb79ac903a00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a8000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac10000000000000000000000001facd50481d827d7d342d79278b9c5a1f9eb6cd7000000000000000000000000abb8621b2f4fb61f083b9f2a033a40086db9030d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000020000000000000000000000006b15b2220973ad753c4f52c2ef748870288f31b100000000000000000000000042398533272ed19ad79bdc32355c530827f08f9f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000013880000000000000000000000000000000000000000000000000000000000001388
-----Decoded View---------------
Arg [0] : _gameMaster (address): 0x51a16E6AEc2924e8886fc323618876e3ED0e4dE5
Arg [1] : _seeder (address): 0x4131aE1e157c91fe083BdCf857A230fb79Ac903a
Arg [2] : _gameCards (address): 0x10FE37BAC405B209f83FF523Fb8D00C0c3F508a8
Arg [3] : _baseCards (address): 0xc8607C5BefA7A7567ca78040bA5C36d181243ac1
Arg [4] : _signer (address): 0x1facD50481D827D7d342D79278B9C5A1F9eB6CD7
Arg [5] : _blastGovernor (address): 0xAbb8621b2F4FB61f083b9f2a033A40086DB9030d
Arg [6] : __beneficiaries (address[]): 0x6b15B2220973Ad753C4f52c2ef748870288F31b1,0x42398533272Ed19Ad79Bdc32355c530827F08F9F
Arg [7] : __weights (uint256[]): 5000,5000
-----Encoded View---------------
14 Constructor Arguments found :
Arg [0] : 00000000000000000000000051a16e6aec2924e8886fc323618876e3ed0e4de5
Arg [1] : 0000000000000000000000004131ae1e157c91fe083bdcf857a230fb79ac903a
Arg [2] : 00000000000000000000000010fe37bac405b209f83ff523fb8d00c0c3f508a8
Arg [3] : 000000000000000000000000c8607c5befa7a7567ca78040ba5c36d181243ac1
Arg [4] : 0000000000000000000000001facd50481d827d7d342d79278b9c5a1f9eb6cd7
Arg [5] : 000000000000000000000000abb8621b2f4fb61f083b9f2a033a40086db9030d
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [9] : 0000000000000000000000006b15b2220973ad753c4f52c2ef748870288f31b1
Arg [10] : 00000000000000000000000042398533272ed19ad79bdc32355c530827f08f9f
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [12] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [13] : 0000000000000000000000000000000000000000000000000000000000001388
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 ]
[ 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.