Source Code
Latest 25 from a total of 1,578 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Stake | 37278982 | 6 mins ago | IN | 0 ETH | 0.00001002 | ||||
| Stake | 37278815 | 8 mins ago | IN | 0 ETH | 0.00000798 | ||||
| Unstake Batch | 37276383 | 25 mins ago | IN | 0 ETH | 0.00001354 | ||||
| Stake | 37275199 | 33 mins ago | IN | 0 ETH | 0.00000807 | ||||
| Unstake | 37273094 | 49 mins ago | IN | 0 ETH | 0.00000696 | ||||
| Unstake | 37273039 | 49 mins ago | IN | 0 ETH | 0.00000687 | ||||
| Unstake | 37273009 | 49 mins ago | IN | 0 ETH | 0.00000672 | ||||
| Unstake | 37272952 | 50 mins ago | IN | 0 ETH | 0.0000097 | ||||
| Stake | 37272723 | 52 mins ago | IN | 0 ETH | 0.00000561 | ||||
| Stake | 37272388 | 54 mins ago | IN | 0 ETH | 0.00000561 | ||||
| Stake | 37272356 | 54 mins ago | IN | 0 ETH | 0.00000561 | ||||
| Stake | 37272331 | 55 mins ago | IN | 0 ETH | 0.0000057 | ||||
| Unstake | 37272162 | 56 mins ago | IN | 0 ETH | 0.00000804 | ||||
| Stake | 37271691 | 1 hr ago | IN | 0 ETH | 0.0000057 | ||||
| Stake | 37271639 | 1 hr ago | IN | 0 ETH | 0.00000561 | ||||
| Stake | 37271608 | 1 hr ago | IN | 0 ETH | 0.00000808 | ||||
| Unstake | 37270203 | 1 hr ago | IN | 0 ETH | 0.00001002 | ||||
| Stake | 37259341 | 2 hrs ago | IN | 0 ETH | 0.00000843 | ||||
| Stake | 37258873 | 2 hrs ago | IN | 0 ETH | 0.00000607 | ||||
| Stake Batch | 37258762 | 2 hrs ago | IN | 0 ETH | 0.00001204 | ||||
| Stake | 37258645 | 2 hrs ago | IN | 0 ETH | 0.00000623 | ||||
| Stake | 37258403 | 2 hrs ago | IN | 0 ETH | 0.00000798 | ||||
| Unstake | 37252971 | 3 hrs ago | IN | 0 ETH | 0.00000864 | ||||
| Stake Batch | 37252755 | 3 hrs ago | IN | 0 ETH | 0.00001411 | ||||
| Stake | 37248217 | 3 hrs ago | IN | 0 ETH | 0.00000697 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 36691938 | 3 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BearishHibearnation
Compiler Version
v0.8.28+commit.7893614a
ZkSolc Version
v1.5.10
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {Ownable} from "solady/src/auth/Ownable.sol";
import {ReentrancyGuard} from "solady/src/utils/ReentrancyGuard.sol";
import {EIP712} from "solady/src/utils/EIP712.sol";
import {SignatureCheckerLib} from "solady/src/utils/SignatureCheckerLib.sol";
import {SafeTransferLib} from "solady/src/utils/ext/zksync/SafeTransferLib.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IHibearnation} from "./interfaces/IHibearnation.sol";
/**
* @title BearishHibearnation
* @author @bearish_af
* @notice NFT staking contract with checkpoint-based accruals and server-signed claims.
* @dev Staking accrues NFT-seconds (time × staked count) per address. Reward credits
* are derived as NFT-seconds × ratePerSecond. Claims are validated via EIP-712
* signatures from a trusted claim signer, with rewards paid from a treasury.
*/
contract BearishHibearnation is
Ownable,
ReentrancyGuard,
EIP712,
IHibearnation
{
using EnumerableSet for EnumerableSet.UintSet;
using SafeTransferLib for address;
/// @notice EIP-712 typehash for claim signatures
bytes32 public constant CLAIM_TYPEHASH =
keccak256(
"Claim(address to,uint256 amount,uint256 deadline,uint256 nonce)"
);
/// @notice Default emission rate (~1,000 BURR/NFT/year)
uint256 public constant DEFAULT_RATE_PER_SECOND = 31_709_791_983_764;
/// @notice DN404 unit representing 1 NFT in ERC20 terms (10,001 × 10^18)
uint256 public constant DN404_UNIT = 10_001 * 1e18;
/// @notice The ERC721 NFT contract for staking
IERC721 public immutable nftContract;
/// @notice The ERC20 reward token address (DN404)
address public immutable rewardToken;
/// @notice Treasury address that holds and pays out rewards
address public treasury;
/// @notice Address authorized to sign claim messages
address public claimSigner;
/// @notice Secondary admin for emergency operations
address public moderator;
/// @notice Emission rate in reward tokens per NFT-second
uint256 public ratePerSecond;
/// @notice Whether staking operations are paused
bool public paused;
/// @notice Whether claims are enabled
bool public claimsEnabled;
/// @notice Stake info by token ID
mapping(uint256 => StakeInfo) public stakes;
/// @notice Set of staked token IDs per address
mapping(address => EnumerableSet.UintSet) private _stakedTokens;
/// @notice Total number of NFTs currently staked
uint256 public totalStaked;
/// @notice Accumulated NFT-seconds per address (rate-independent)
mapping(address => uint256) public accruedNFTSeconds;
/// @notice Last checkpoint timestamp per address
mapping(address => uint48) public lastCheckpoint;
/// @notice Records depositor for NFTs sent via safeTransfer (not stake())
mapping(uint256 => address) public untrackedDepositor;
/// @notice Cumulative claimed amount per address
mapping(address => uint256) public claimedAmount;
/// @notice Claim nonce per address (prevents replay)
mapping(address => uint256) public nonces;
/// @dev Reverts if contract is paused
modifier whenNotPaused() {
if (paused) revert Paused();
_;
}
/// @dev Reverts if caller is not owner or moderator
modifier onlyOwnerOrModerator() {
if (msg.sender != owner() && msg.sender != moderator)
revert Unauthorized();
_;
}
/**
* @notice Initializes the staking contract
* @param _nftContract Address of the ERC721 NFT contract to stake
* @param _rewardToken Address of the DN404/ERC20 reward token
* @param _treasury Address holding reward tokens (must approve this contract)
* @param _owner Contract owner address
* @param _claimSigner Address authorized to sign claim messages
* @param _moderator Secondary admin for emergency functions (can be zero)
* @param _ratePerSecond Initial emission rate per NFT-second
*/
constructor(
address _nftContract,
address _rewardToken,
address _treasury,
address _owner,
address _claimSigner,
address _moderator,
uint256 _ratePerSecond
) {
if (_nftContract == address(0)) revert ZeroAddress();
if (_rewardToken == address(0)) revert ZeroAddress();
if (_treasury == address(0)) revert ZeroAddress();
if (_owner == address(0)) revert ZeroAddress();
if (_claimSigner == address(0)) revert ZeroAddress();
nftContract = IERC721(_nftContract);
rewardToken = _rewardToken;
treasury = _treasury;
claimSigner = _claimSigner;
moderator = _moderator;
ratePerSecond = _ratePerSecond;
claimsEnabled = true;
_initializeOwner(_owner);
}
// ══════════════════════════════════════════════════════════════════════════
// Checkpoints
// ══════════════════════════════════════════════════════════════════════════
/**
* @dev Finalizes pending NFT-seconds for a user and updates their checkpoint
* @param user Address to checkpoint
*/
function _checkpoint(address user) internal {
uint48 last = lastCheckpoint[user];
uint256 count = _stakedTokens[user].length();
if (last != 0 && count > 0) {
uint256 elapsed = block.timestamp - last;
accruedNFTSeconds[user] += elapsed * count;
}
lastCheckpoint[user] = uint48(block.timestamp);
}
/**
* @notice Manually checkpoint a user's accrued NFT-seconds
* @dev Useful for locking in accruals before a rate change
* @param user Address to checkpoint
*/
function checkpoint(address user) external {
_checkpoint(user);
emit Checkpointed(user, accruedNFTSeconds[user]);
}
/**
* @notice Checkpoint multiple users in a single transaction
* @param users Array of addresses to checkpoint
*/
function checkpointBatch(address[] calldata users) external {
uint256 len = users.length;
for (uint256 i; i < len; ++i) {
address user = users[i];
_checkpoint(user);
emit Checkpointed(user, accruedNFTSeconds[user]);
}
}
// ══════════════════════════════════════════════════════════════════════════
// Staking
// ══════════════════════════════════════════════════════════════════════════
/**
* @notice Stake a single NFT
* @dev Caller must own the token and have approved this contract
* @param tokenId Token ID to stake
*/
function stake(uint256 tokenId) external nonReentrant whenNotPaused {
_stake(msg.sender, tokenId);
}
/**
* @notice Stake multiple NFTs in a single transaction
* @dev Caller must own all tokens and have approved this contract
* @param tokenIds Array of token IDs to stake
*/
function stakeBatch(
uint256[] calldata tokenIds
) external nonReentrant whenNotPaused {
address staker = msg.sender;
_checkpoint(staker);
IERC721 nft = nftContract;
uint256 len = tokenIds.length;
uint48 ts = uint48(block.timestamp);
for (uint256 i; i < len; ++i) {
uint256 tokenId = tokenIds[i];
if (nft.ownerOf(tokenId) != staker) revert NotTokenOwner();
nft.transferFrom(staker, address(this), tokenId);
stakes[tokenId] = StakeInfo({owner: staker, stakedAt: ts});
if (!_stakedTokens[staker].add(tokenId))
revert TokenAlreadyStaked();
emit Staked(staker, tokenId, ts);
emit Locked(tokenId);
}
totalStaked += len;
}
/**
* @notice Unstake a single NFT
* @dev Returns NFT to the staker, preserves accrued NFT-seconds
* @param tokenId Token ID to unstake
*/
function unstake(uint256 tokenId) external nonReentrant {
_unstake(msg.sender, tokenId);
}
/**
* @notice Unstake multiple NFTs in a single transaction
* @param tokenIds Array of token IDs to unstake
*/
function unstakeBatch(uint256[] calldata tokenIds) external nonReentrant {
address staker = msg.sender;
_checkpoint(staker);
IERC721 nft = nftContract;
uint256 len = tokenIds.length;
uint256 nftSeconds = totalNFTSeconds(staker);
for (uint256 i; i < len; ++i) {
uint256 tokenId = tokenIds[i];
StakeInfo storage info = stakes[tokenId];
if (info.owner == address(0)) revert TokenNotStaked();
if (info.owner != staker) revert NotStakeOwner();
uint48 duration = uint48(block.timestamp - info.stakedAt);
delete stakes[tokenId];
if (!_stakedTokens[staker].remove(tokenId)) revert TokenNotInSet();
nft.transferFrom(address(this), staker, tokenId);
emit Unstaked(staker, tokenId, duration, nftSeconds);
emit Unlocked(tokenId);
}
totalStaked -= len;
}
// ══════════════════════════════════════════════════════════════════════════
// Views
// ══════════════════════════════════════════════════════════════════════════
/**
* @notice Returns the address that staked a specific token
* @dev This is staking-specific, not standard ERC721 ownerOf
* @param tokenId Token ID to query
* @return Address of the staker, or zero if not staked
*/
function stakerOf(uint256 tokenId) external view returns (address) {
return stakes[tokenId].owner;
}
/**
* @notice Returns all staked token IDs for an address
* @param staker Address to query
* @return Array of staked token IDs
*/
function stakedTokensOf(
address staker
) external view returns (uint256[] memory) {
return _getStakedTokensArray(staker);
}
/**
* @notice Returns the number of NFTs staked by an address
* @param staker Address to query
* @return Number of staked NFTs
*/
function stakedBalanceOf(address staker) external view returns (uint256) {
return _stakedTokens[staker].length();
}
/**
* @notice Check if a token is currently staked
* @param tokenId Token ID to check
* @return True if staked
*/
function isStaked(uint256 tokenId) external view returns (bool) {
return stakes[tokenId].owner != address(0);
}
/**
* @notice Returns how long a token has been staked
* @param tokenId Token ID to query
* @return Duration in seconds, or 0 if not staked
*/
function currentStakeDuration(
uint256 tokenId
) external view returns (uint48) {
StakeInfo storage info = stakes[tokenId];
if (info.owner == address(0)) return 0;
return uint48(block.timestamp - info.stakedAt);
}
/**
* @notice Returns stake info for a token
* @param tokenId Token ID to query
* @return staker Address of the staker
* @return stakedAt Timestamp when staked
*/
function getStakeInfo(
uint256 tokenId
) external view returns (address staker, uint48 stakedAt) {
StakeInfo storage info = stakes[tokenId];
return (info.owner, info.stakedAt);
}
/**
* @notice Returns total NFT-seconds (finalized + pending) for a user
* @dev This is rate-independent; multiply by ratePerSecond for credits
* @param user Address to query
* @return Total NFT-seconds accrued
*/
function totalNFTSeconds(address user) public view returns (uint256) {
uint256 base = accruedNFTSeconds[user];
uint48 last = lastCheckpoint[user];
uint256 count = _stakedTokens[user].length();
if (last == 0 || count == 0) return base;
return base + (block.timestamp - last) * count;
}
/**
* @notice Returns uncheckpointed NFT-seconds for a user
* @param user Address to query
* @return Pending NFT-seconds not yet finalized
*/
function pendingNFTSeconds(address user) external view returns (uint256) {
uint48 last = lastCheckpoint[user];
uint256 count = _stakedTokens[user].length();
if (last == 0 || count == 0) return 0;
return (block.timestamp - last) * count;
}
/**
* @notice Returns reward credits (NFT-seconds × ratePerSecond)
* @dev Changes retroactively when ratePerSecond is updated
* @param user Address to query
* @return Reward credits in token wei
*/
function rewardCredits(address user) public view returns (uint256) {
return totalNFTSeconds(user) * ratePerSecond;
}
/**
* @notice Alias for totalNFTSeconds for backward compatibility
* @param user Address to query
* @return Total NFT-seconds accrued
*/
function totalAccruedTime(address user) external view returns (uint256) {
return totalNFTSeconds(user);
}
/**
* @notice Returns the reward token balance in the treasury
* @return Treasury balance in token wei
*/
function treasuryBalance() external view returns (uint256) {
return IERC20(rewardToken).balanceOf(treasury);
}
/**
* @notice Returns the treasury's allowance for this contract
* @return Allowance in token wei
*/
function treasuryAllowance() external view returns (uint256) {
return IERC20(rewardToken).allowance(treasury, address(this));
}
// ══════════════════════════════════════════════════════════════════════════
// Claims
// ══════════════════════════════════════════════════════════════════════════
/**
* @notice Claim reward tokens using a server-signed authorization
* @dev Amount is cumulative; contract tracks already-claimed amounts
* @param amount Cumulative amount authorized to claim
* @param deadline Timestamp after which signature expires
* @param nonce Expected nonce for replay protection
* @param signature EIP-712 signature from claimSigner
*/
function claim(
uint256 amount,
uint256 deadline,
uint256 nonce,
bytes calldata signature
) external nonReentrant {
if (!claimsEnabled) revert ClaimsNotEnabled();
if (block.timestamp > deadline) revert SignatureExpired();
if (nonce != nonces[msg.sender]) revert InvalidNonce();
uint256 alreadyClaimed = claimedAmount[msg.sender];
if (amount <= alreadyClaimed) revert NothingToClaim();
bytes32 digest = _hashTypedData(
keccak256(
abi.encode(CLAIM_TYPEHASH, msg.sender, amount, deadline, nonce)
)
);
if (
!SignatureCheckerLib.isValidSignatureNowCalldata(
claimSigner,
digest,
signature
)
) {
revert InvalidSignature();
}
uint256 toClaim = amount - alreadyClaimed;
nonces[msg.sender] = nonce + 1;
claimedAmount[msg.sender] = amount;
rewardToken.safeTransferFrom(treasury, msg.sender, toClaim);
emit Claimed(msg.sender, toClaim, amount);
}
/**
* @notice Returns the current nonce for a user
* @param user Address to query
* @return Current nonce
*/
function getNonce(address user) external view returns (uint256) {
return nonces[user];
}
/**
* @notice Returns cumulative claimed amount for a user
* @param user Address to query
* @return Total amount claimed
*/
function getClaimedAmount(address user) external view returns (uint256) {
return claimedAmount[user];
}
/**
* @notice Alias for totalNFTSeconds
* @param user Address to query
* @return Total NFT-seconds accrued
*/
function getAccruedTime(address user) external view returns (uint256) {
return totalNFTSeconds(user);
}
// ══════════════════════════════════════════════════════════════════════════
// Admin
// ══════════════════════════════════════════════════════════════════════════
/**
* @notice Update the claim signer address
* @param _claimSigner New signer address
*/
function setClaimSigner(address _claimSigner) external onlyOwner {
if (_claimSigner == address(0)) revert ZeroAddress();
emit SignerUpdated(claimSigner, _claimSigner);
claimSigner = _claimSigner;
}
/**
* @notice Update the moderator address
* @param _moderator New moderator address (can be zero to disable)
*/
function setModerator(address _moderator) external onlyOwner {
emit ModeratorUpdated(moderator, _moderator);
moderator = _moderator;
}
/**
* @notice Update the treasury address
* @param _treasury New treasury address
*/
function setTreasury(address _treasury) external onlyOwner {
if (_treasury == address(0)) revert ZeroAddress();
emit TreasuryUpdated(treasury, _treasury);
treasury = _treasury;
}
/**
* @notice Update the emission rate
* @dev Affects rewardCredits() retroactively for all users
* @param _ratePerSecond New rate per NFT-second
*/
function setRatePerSecond(uint256 _ratePerSecond) external onlyOwner {
emit RateUpdated(ratePerSecond, _ratePerSecond);
ratePerSecond = _ratePerSecond;
}
/**
* @notice Enable or disable claims
* @param _enabled Whether claims should be enabled
*/
function setClaimsEnabled(bool _enabled) external onlyOwner {
claimsEnabled = _enabled;
emit ClaimsEnabledUpdated(_enabled, msg.sender);
}
/**
* @notice Pause staking operations
*/
function pause() external onlyOwner {
paused = true;
emit PausedStateChanged(true, msg.sender);
}
/**
* @notice Unpause staking operations
*/
function unpause() external onlyOwner {
paused = false;
emit PausedStateChanged(false, msg.sender);
}
// ══════════════════════════════════════════════════════════════════════════
// Emergency
// ══════════════════════════════════════════════════════════════════════════
/**
* @notice Emergency withdraw a single staked NFT back to its owner
* @dev Only callable by owner or moderator. Preserves accrued NFT-seconds.
* @param tokenId Token ID to withdraw
*/
function emergencyWithdrawNFT(
uint256 tokenId
) external onlyOwnerOrModerator nonReentrant {
StakeInfo storage info = stakes[tokenId];
address originalOwner = info.owner;
if (originalOwner == address(0)) revert TokenNotStaked();
_checkpoint(originalOwner);
delete stakes[tokenId];
if (!_stakedTokens[originalOwner].remove(tokenId))
revert TokenNotInSet();
--totalStaked;
nftContract.transferFrom(address(this), originalOwner, tokenId);
emit EmergencyNFTWithdraw(tokenId, originalOwner, msg.sender);
emit Unlocked(tokenId);
}
/**
* @notice Emergency withdraw multiple staked NFTs back to their owners
* @param tokenIds Array of token IDs to withdraw
*/
function emergencyWithdrawNFTBatch(
uint256[] calldata tokenIds
) external onlyOwnerOrModerator nonReentrant {
IERC721 nft = nftContract;
uint256 len = tokenIds.length;
for (uint256 i; i < len; ++i) {
uint256 tokenId = tokenIds[i];
StakeInfo storage info = stakes[tokenId];
address originalOwner = info.owner;
if (originalOwner == address(0)) revert TokenNotStaked();
_checkpoint(originalOwner);
delete stakes[tokenId];
if (!_stakedTokens[originalOwner].remove(tokenId))
revert TokenNotInSet();
--totalStaked;
nft.transferFrom(address(this), originalOwner, tokenId);
emit EmergencyNFTWithdraw(tokenId, originalOwner, msg.sender);
emit Unlocked(tokenId);
}
}
/**
* @notice Rescue an NFT sent directly via safeTransfer (not stake())
* @dev Permissionless - returns NFT to recorded depositor
* @param tokenId Token ID to rescue
*/
function rescueUntrackedNFT(uint256 tokenId) external nonReentrant {
if (stakes[tokenId].owner != address(0)) revert TokenAlreadyTracked();
if (nftContract.ownerOf(tokenId) != address(this))
revert TokenNotHeld();
address depositor = untrackedDepositor[tokenId];
if (depositor == address(0)) revert ZeroAddress();
delete untrackedDepositor[tokenId];
nftContract.transferFrom(address(this), depositor, tokenId);
emit NFTRescued(tokenId, depositor, msg.sender);
}
/**
* @notice Admin rescue for NFTs without a recorded depositor
* @dev Fallback when permissionless rescue is not possible
* @param tokenId Token ID to rescue
* @param to Destination address
*/
function rescueUntrackedNFTAdmin(
uint256 tokenId,
address to
) external onlyOwnerOrModerator nonReentrant {
if (to == address(0)) revert ZeroAddress();
if (stakes[tokenId].owner != address(0)) revert TokenAlreadyTracked();
if (nftContract.ownerOf(tokenId) != address(this))
revert TokenNotHeld();
delete untrackedDepositor[tokenId];
nftContract.transferFrom(address(this), to, tokenId);
emit NFTRescued(tokenId, to, msg.sender);
}
/**
* @notice Withdraw accidentally sent ERC20 tokens (not reward token)
* @param token Token address to withdraw
* @param amount Amount to withdraw
*/
function emergencyWithdrawTokens(
address token,
uint256 amount
) external onlyOwner {
if (token == rewardToken) revert CannotWithdrawRewardToken();
token.safeTransfer(owner(), amount);
emit EmergencyTokenWithdraw(token, amount, owner(), msg.sender);
}
// ══════════════════════════════════════════════════════════════════════════
// Internal
// ══════════════════════════════════════════════════════════════════════════
/**
* @dev Converts EnumerableSet to memory array
*/
function _getStakedTokensArray(
address staker
) internal view returns (uint256[] memory result) {
EnumerableSet.UintSet storage tokens = _stakedTokens[staker];
uint256 len = tokens.length();
result = new uint256[](len);
for (uint256 i; i < len; ++i) {
result[i] = tokens.at(i);
}
}
/**
* @dev Internal stake logic
*/
function _stake(address staker, uint256 tokenId) internal {
_checkpoint(staker);
IERC721 nft = nftContract;
if (nft.ownerOf(tokenId) != staker) revert NotTokenOwner();
nft.transferFrom(staker, address(this), tokenId);
stakes[tokenId] = StakeInfo({
owner: staker,
stakedAt: uint48(block.timestamp)
});
if (!_stakedTokens[staker].add(tokenId)) revert TokenAlreadyStaked();
++totalStaked;
emit Staked(staker, tokenId, uint48(block.timestamp));
emit Locked(tokenId);
}
/**
* @dev Internal unstake logic
*/
function _unstake(address staker, uint256 tokenId) internal {
_checkpoint(staker);
StakeInfo storage info = stakes[tokenId];
if (info.owner == address(0)) revert TokenNotStaked();
if (info.owner != staker) revert NotStakeOwner();
uint48 duration = uint48(block.timestamp - info.stakedAt);
delete stakes[tokenId];
if (!_stakedTokens[staker].remove(tokenId)) revert TokenNotInSet();
--totalStaked;
nftContract.transferFrom(address(this), staker, tokenId);
emit Unstaked(staker, tokenId, duration, totalNFTSeconds(staker));
emit Unlocked(tokenId);
}
/**
* @dev Returns EIP-712 domain name and version
*/
function _domainNameAndVersion()
internal
pure
override
returns (string memory name, string memory version)
{
return ("BearishHibearnation", "1");
}
/**
* @notice ERC721 receiver hook
* @dev Records depositor for NFTs sent via safeTransfer for rescue
*/
function onERC721Received(
address,
address from,
uint256 tokenId,
bytes calldata
) external override returns (bytes4) {
if (msg.sender != address(nftContract)) revert InvalidNFTContract();
if (paused) revert Paused();
if (from != address(0) && stakes[tokenId].owner == address(0)) {
untrackedDepositor[tokenId] = from;
}
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
/**
* @title IHibearnation
* @author @bearish_af
* @notice Interface for the BearishHibearnation NFT staking contract
* @dev Defines all external functions, events, errors, and structs for the staking system
*/
interface IHibearnation is IERC721Receiver {
struct StakeInfo {
address owner;
uint48 stakedAt;
}
event Staked(
address indexed staker,
uint256 indexed tokenId,
uint48 timestamp
);
event Unstaked(
address indexed staker,
uint256 indexed tokenId,
uint48 stakedDuration,
uint256 totalNFTSeconds
);
event Locked(uint256 tokenId);
event Unlocked(uint256 tokenId);
event Claimed(
address indexed user,
uint256 amountClaimed,
uint256 totalClaimed
);
event Checkpointed(address indexed user, uint256 accruedNFTSeconds);
event EmergencyNFTWithdraw(
uint256 indexed tokenId,
address indexed to,
address indexed by
);
event NFTRescued(
uint256 indexed tokenId,
address indexed to,
address indexed by
);
event EmergencyTokenWithdraw(
address indexed token,
uint256 amount,
address indexed to,
address indexed by
);
event SignerUpdated(address indexed oldSigner, address indexed newSigner);
event ModeratorUpdated(
address indexed oldModerator,
address indexed newModerator
);
event TreasuryUpdated(
address indexed oldTreasury,
address indexed newTreasury
);
event RateUpdated(uint256 oldRate, uint256 newRate);
event ClaimsEnabledUpdated(bool enabled, address indexed by);
event PausedStateChanged(bool paused, address indexed by);
error ZeroAddress();
error NotTokenOwner();
error TokenNotStaked();
error NotStakeOwner();
error TokenAlreadyStaked();
error TokenNotInSet();
error TokenAlreadyTracked();
error TokenNotHeld();
error CannotWithdrawRewardToken();
error InvalidSignature();
error SignatureExpired();
error InvalidNonce();
error NothingToClaim();
error ClaimsNotEnabled();
error Paused();
error InvalidNFTContract();
function CLAIM_TYPEHASH() external view returns (bytes32);
function DEFAULT_RATE_PER_SECOND() external view returns (uint256);
function DN404_UNIT() external view returns (uint256);
function nftContract() external view returns (IERC721);
function rewardToken() external view returns (address);
function treasury() external view returns (address);
function claimSigner() external view returns (address);
function moderator() external view returns (address);
function ratePerSecond() external view returns (uint256);
function paused() external view returns (bool);
function claimsEnabled() external view returns (bool);
function totalStaked() external view returns (uint256);
function stakes(
uint256 tokenId
) external view returns (address staker, uint48 stakedAt);
function untrackedDepositor(
uint256 tokenId
) external view returns (address);
function accruedNFTSeconds(address user) external view returns (uint256);
function lastCheckpoint(address user) external view returns (uint48);
function claimedAmount(address user) external view returns (uint256);
function nonces(address user) external view returns (uint256);
function checkpoint(address user) external;
function checkpointBatch(address[] calldata users) external;
function stake(uint256 tokenId) external;
function stakeBatch(uint256[] calldata tokenIds) external;
function unstake(uint256 tokenId) external;
function unstakeBatch(uint256[] calldata tokenIds) external;
function stakerOf(uint256 tokenId) external view returns (address);
function stakedTokensOf(
address staker
) external view returns (uint256[] memory);
function stakedBalanceOf(address staker) external view returns (uint256);
function isStaked(uint256 tokenId) external view returns (bool);
function currentStakeDuration(
uint256 tokenId
) external view returns (uint48);
function getStakeInfo(
uint256 tokenId
) external view returns (address staker, uint48 stakedAt);
function totalNFTSeconds(address user) external view returns (uint256);
function pendingNFTSeconds(address user) external view returns (uint256);
function rewardCredits(address user) external view returns (uint256);
function totalAccruedTime(address user) external view returns (uint256);
function treasuryBalance() external view returns (uint256);
function treasuryAllowance() external view returns (uint256);
function claim(
uint256 amount,
uint256 deadline,
uint256 nonce,
bytes calldata signature
) external;
function getNonce(address user) external view returns (uint256);
function getClaimedAmount(address user) external view returns (uint256);
function getAccruedTime(address user) external view returns (uint256);
function setClaimSigner(address _claimSigner) external;
function setModerator(address _moderator) external;
function setTreasury(address _treasury) external;
function setRatePerSecond(uint256 _ratePerSecond) external;
function setClaimsEnabled(bool _enabled) external;
function pause() external;
function unpause() external;
function emergencyWithdrawNFT(uint256 tokenId) external;
function emergencyWithdrawNFTBatch(uint256[] calldata tokenIds) external;
function rescueUntrackedNFT(uint256 tokenId) external;
function rescueUntrackedNFTAdmin(uint256 tokenId, address to) external;
function emergencyWithdrawTokens(address token, uint256 amount) external;
}// 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.4;
/// @notice Contract for EIP-712 typed structured data hashing and signing.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol)
/// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol)
///
/// @dev Note, this implementation:
/// - Uses `address(this)` for the `verifyingContract` field.
/// - Does NOT use the optional EIP-712 salt.
/// - Does NOT use any EIP-712 extensions.
/// This is for simplicity and to save gas.
/// If you need to customize, please fork / modify accordingly.
abstract contract EIP712 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS AND IMMUTABLES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
bytes32 internal constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
uint256 private immutable _cachedThis;
uint256 private immutable _cachedChainId;
bytes32 private immutable _cachedNameHash;
bytes32 private immutable _cachedVersionHash;
bytes32 private immutable _cachedDomainSeparator;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTRUCTOR */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Cache the hashes for cheaper runtime gas costs.
/// In the case of upgradeable contracts (i.e. proxies),
/// or if the chain id changes due to a hard fork,
/// the domain separator will be seamlessly calculated on-the-fly.
constructor() {
_cachedThis = uint256(uint160(address(this)));
_cachedChainId = block.chainid;
string memory name;
string memory version;
if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion();
bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name));
bytes32 versionHash =
_domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version));
_cachedNameHash = nameHash;
_cachedVersionHash = versionHash;
bytes32 separator;
if (!_domainNameAndVersionMayChange()) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), versionHash)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
separator := keccak256(m, 0xa0)
}
}
_cachedDomainSeparator = separator;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Please override this function to return the domain name and version.
/// ```
/// function _domainNameAndVersion()
/// internal
/// pure
/// virtual
/// returns (string memory name, string memory version)
/// {
/// name = "Solady";
/// version = "1";
/// }
/// ```
///
/// Note: If the returned result may change after the contract has been deployed,
/// you must override `_domainNameAndVersionMayChange()` to return true.
function _domainNameAndVersion()
internal
view
virtual
returns (string memory name, string memory version);
/// @dev Returns if `_domainNameAndVersion()` may change
/// after the contract has been deployed (i.e. after the constructor).
/// Default: false.
function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the EIP-712 domain separator.
function _domainSeparator() internal view virtual returns (bytes32 separator) {
if (_domainNameAndVersionMayChange()) {
separator = _buildDomainSeparator();
} else {
separator = _cachedDomainSeparator;
if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
}
}
/// @dev Returns the hash of the fully encoded EIP-712 message for this domain,
/// given `structHash`, as defined in
/// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
///
/// The hash can be used together with {ECDSA-recover} to obtain the signer of a message:
/// ```
/// bytes32 digest = _hashTypedData(keccak256(abi.encode(
/// keccak256("Mail(address to,string contents)"),
/// mailTo,
/// keccak256(bytes(mailContents))
/// )));
/// address signer = ECDSA.recover(digest, signature);
/// ```
function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) {
// We will use `digest` to store the domain separator to save a bit of gas.
if (_domainNameAndVersionMayChange()) {
digest = _buildDomainSeparator();
} else {
digest = _cachedDomainSeparator;
if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator();
}
/// @solidity memory-safe-assembly
assembly {
// Compute the digest.
mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
mstore(0x1a, digest) // Store the domain separator.
mstore(0x3a, structHash) // Store the struct hash.
digest := keccak256(0x18, 0x42)
// Restore the part of the free memory slot that was overwritten.
mstore(0x3a, 0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EIP-5267 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev See: https://eips.ethereum.org/EIPS/eip-5267
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
fields = hex"0f"; // `0b01111`.
(name, version) = _domainNameAndVersion();
chainId = block.chainid;
verifyingContract = address(this);
salt = salt; // `bytes32(0)`.
extensions = extensions; // `new uint256[](0)`.
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the EIP-712 domain separator.
function _buildDomainSeparator() private view returns (bytes32 separator) {
// We will use `separator` to store the name hash to save a bit of gas.
bytes32 versionHash;
if (_domainNameAndVersionMayChange()) {
(string memory name, string memory version) = _domainNameAndVersion();
separator = keccak256(bytes(name));
versionHash = keccak256(bytes(version));
} else {
separator = _cachedNameHash;
versionHash = _cachedVersionHash;
}
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Load the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), separator) // Name hash.
mstore(add(m, 0x40), versionHash)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
separator := keccak256(m, 0xa0)
}
}
/// @dev Returns if the cached domain separator has been invalidated.
function _cachedDomainSeparatorInvalidated() private view returns (bool result) {
uint256 cachedChainId = _cachedChainId;
uint256 cachedThis = _cachedThis;
/// @solidity memory-safe-assembly
assembly {
result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Signature verification helper that supports both ECDSA signatures from EOAs
/// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol)
///
/// @dev Note:
/// - The signature checking functions use the ecrecover precompile (0x1).
/// - The `bytes memory signature` variants use the identity precompile (0x4)
/// to copy memory internally.
/// - Unlike ECDSA signatures, contract signatures are revocable.
/// - 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 SignatureCheckerLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIGNATURE CHECKING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns whether `signature` is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
switch mload(signature)
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { break }
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
// Copy the `signature` over.
let n := add(0x20, mload(signature))
let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n)
isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20)
isValid := and(eq(mload(d), f), and(isValid, copied))
break
}
}
}
/// @dev Returns whether `signature` is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
switch signature.length
case 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`.
}
case 65 {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.
}
default { break }
mstore(0x00, hash)
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), signature.length)
// Copy the `signature` over.
calldatacopy(add(m, 0x64), signature.offset, signature.length)
isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
isValid := and(eq(mload(d), f), isValid)
break
}
}
}
/// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
break
}
}
}
/// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
mstore(0x00, hash)
mstore(0x20, and(v, 0xff)) // `v`.
mstore(0x40, r) // `r`.
mstore(0x60, s) // `s`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), s) // `s`.
mstore8(add(m, 0xa4), v) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC1271 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: These ERC1271 operations do NOT have an ECDSA fallback.
/// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature)
internal
view
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
// Copy the `signature` over.
let n := add(0x20, mload(signature))
let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n)
isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20)
isValid := and(eq(mload(d), f), and(isValid, copied))
}
}
/// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
function isValidERC1271SignatureNowCalldata(
address signer,
bytes32 hash,
bytes calldata signature
) internal view returns (bool isValid) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), signature.length)
// Copy the `signature` over.
calldatacopy(add(m, 0x64), signature.offset, signature.length)
isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
isValid := and(eq(mload(d), f), isValid)
}
}
/// @dev Returns whether the signature (`r`, `vs`) is valid for `hash`
/// for an ERC1271 `signer` contract.
function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
}
}
/// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash`
/// for an ERC1271 `signer` contract.
function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), s) // `s`.
mstore8(add(m, 0xa4), v) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC6492 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: These ERC6492 operations now include an ECDSA fallback at the very end.
// The calldata variants are excluded for brevity.
/// @dev Returns whether `signature` is valid for `hash`.
/// If the signature is postfixed with the ERC6492 magic number, it will attempt to
/// deploy / prepare the `signer` smart account before doing a regular ERC1271 check.
/// Note: This function is NOT reentrancy safe.
/// The verifier must be deployed.
/// Otherwise, the function will return false if `signer` is not yet deployed / prepared.
/// See: https://gist.github.com/Vectorized/011d6becff6e0a73e42fe100f8d7ef04
/// With a dedicated verifier, this function is safe to use in contracts
/// that have been granted special permissions.
function isValidERC6492SignatureNowAllowSideEffects(
address signer,
bytes32 hash,
bytes memory signature
) internal returns (bool isValid) {
/// @solidity memory-safe-assembly
assembly {
function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
let m_ := mload(0x40)
let f_ := shl(224, 0x1626ba7e)
mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m_, 0x04), hash_)
let d_ := add(m_, 0x24)
mstore(d_, 0x40) // The offset of the `signature` in the calldata.
let n_ := add(0x20, mload(signature_))
let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)
_isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
_isValid := and(eq(mload(d_), f_), and(_isValid, copied_))
}
let noCode := iszero(extcodesize(signer))
let n := mload(signature)
for {} 1 {} {
if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) }
break
}
if iszero(noCode) {
let o := add(signature, 0x20) // Signature bytes.
isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))
if isValid { break }
}
let m := mload(0x40)
mstore(m, signer)
mstore(add(m, 0x20), hash)
pop(
call(
gas(), // Remaining gas.
0x0000bc370E4DC924F427d84e2f4B9Ec81626ba7E, // Non-reverting verifier.
0, // Send zero ETH.
m, // Start of memory.
add(returndatasize(), 0x40), // Length of calldata in memory.
staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.
0x00 // Length of returndata to write.
)
)
isValid := returndatasize()
break
}
// Do `ecrecover` fallback if `noCode && !isValid`.
for {} gt(noCode, isValid) {} {
switch n
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { break }
let m := mload(0x40)
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
}
}
/// @dev Returns whether `signature` is valid for `hash`.
/// If the signature is postfixed with the ERC6492 magic number, it will attempt
/// to use a reverting verifier to deploy / prepare the `signer` smart account
/// and do a `isValidSignature` check via the reverting verifier.
/// Note: This function is reentrancy safe.
/// The reverting verifier must be deployed.
/// Otherwise, the function will return false if `signer` is not yet deployed / prepared.
/// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad
function isValidERC6492SignatureNow(address signer, bytes32 hash, bytes memory signature)
internal
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
let m_ := mload(0x40)
let f_ := shl(224, 0x1626ba7e)
mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m_, 0x04), hash_)
let d_ := add(m_, 0x24)
mstore(d_, 0x40) // The offset of the `signature` in the calldata.
let n_ := add(0x20, mload(signature_))
let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)
_isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
_isValid := and(eq(mload(d_), f_), and(_isValid, copied_))
}
let noCode := iszero(extcodesize(signer))
let n := mload(signature)
for {} 1 {} {
if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) }
break
}
if iszero(noCode) {
let o := add(signature, 0x20) // Signature bytes.
isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))
if isValid { break }
}
let m := mload(0x40)
mstore(m, signer)
mstore(add(m, 0x20), hash)
let willBeZeroIfRevertingVerifierExists :=
call(
gas(), // Remaining gas.
0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier.
0, // Send zero ETH.
m, // Start of memory.
add(returndatasize(), 0x40), // Length of calldata in memory.
staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.
0x00 // Length of returndata to write.
)
isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists)
break
}
// Do `ecrecover` fallback if `noCode && !isValid`.
for {} gt(noCode, isValid) {} {
switch n
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { break }
let m := mload(0x40)
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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 Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unauthorized reentrant call.
error Reentrancy();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
/// 9 bytes is large enough to avoid collisions with lower slots,
/// but not too large to result in excessive bytecode bloat.
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* REENTRANCY GUARD */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Guards a function from reentrancy.
modifier nonReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
sstore(_REENTRANCY_GUARD_SLOT, address())
}
_;
/// @solidity memory-safe-assembly
assembly {
sstore(_REENTRANCY_GUARD_SLOT, codesize())
}
}
/// @dev Guards a view function from read-only reentrancy.
modifier nonReadReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @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`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC-721 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 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) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* 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;
/**
* @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;
/**
* @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 address zero.
*
* 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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {SingleUseETHVault} from "./SingleUseETHVault.sol";
/// @notice Library for force safe transferring ETH and ERC20s in ZKsync.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ext/zksync/SafeTransferLib.sol)
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A single use ETH vault has been created for `to`, with `amount`.
event SingleUseETHVaultCreated(address indexed to, uint256 amount, address vault);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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();
/// @dev The ERC20 `totalSupply` query has failed.
error TotalSupplyQueryFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @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 = 1000000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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, 0x00, 0x00, 0x00, 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(), 0x00, 0x00, 0x00, 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
/// If force transfer is used, returns the vault. Else returns `address(0)`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (address vault)
{
if (amount == uint256(0)) return address(0); // Early return if `amount` is zero.
uint256 selfBalanceBefore = address(this).balance;
/// @solidity memory-safe-assembly
assembly {
if lt(selfBalanceBefore, amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
pop(call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00))
}
if (address(this).balance == selfBalanceBefore) {
vault = address(new SingleUseETHVault());
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, shr(96, shl(96, to)))
if iszero(call(gas(), vault, amount, 0x00, 0x20, 0x00, 0x00)) { revert(0x00, 0x00) }
}
emit SingleUseETHVaultCreated(to, amount, vault);
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
/// If force transfer is used, returns the vault. Else returns `address(0)`.
function forceSafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (address vault)
{
vault = forceSafeTransferETH(to, address(this).balance, gasStipend);
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
/// If force transfer is used, returns the vault. Else returns `address(0)`.
function forceSafeTransferETH(address to, uint256 amount) internal returns (address vault) {
vault = forceSafeTransferETH(to, amount, GAS_STIPEND_NO_GRIEF);
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
/// If force transfer is used, returns the vault. Else returns `address(0)`.
function forceSafeTransferAllETH(address to) internal returns (address vault) {
vault = forceSafeTransferETH(to, address(this).balance, GAS_STIPEND_NO_GRIEF);
}
/// @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, 0x00, 0x00, 0x00, 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(), 0x00, 0x00, 0x00, 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)`.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
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 `from` to `to`.
///
/// The `from` account must have at least `amount` approved for the current contract to manage.
function trySafeTransferFrom(address token, address from, address to, uint256 amount)
internal
returns (bool success)
{
/// @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)`.
success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
}
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.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
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.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
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.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
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)`.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
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.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
// Check the `extcodesize` again just in case the token selfdestructs lol.
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
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( // The arguments of `mul` are evaluated from right to left.
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)
)
)
}
}
/// @dev Returns the total supply of the `token`.
/// Reverts if the token does not exist or does not implement `totalSupply()`.
function totalSupply(address token) internal view returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x18160ddd) // `totalSupply()`.
if iszero(
and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20))
) {
mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`.
revert(0x1c, 0x04)
}
result := mload(0x00)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice A single-use vault that allows a designated caller to withdraw all ETH in it.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ext/zksync/SingleUseETHVault.sol)
contract SingleUseETHVault {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unable to withdraw all.
error WithdrawAllFailed();
/// @dev Not authorized.
error Unauthorized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* WITHDRAW ALL */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
fallback() external payable virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x40, 0) // Optimization trick to remove free memory pointer initialization.
let owner := sload(0)
// Initialization.
if iszero(owner) {
sstore(0, calldataload(0x00)) // Store the owner.
return(0x00, 0x00) // Early return.
}
// Authorization check.
if iszero(eq(caller(), owner)) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
let to := calldataload(0x00)
// If the calldata is less than 32 bytes, zero-left-pad it to 32 bytes.
// Then use the rightmost 20 bytes of the word as the `to` address.
// This allows for the calldata to be `abi.encode(to)` or `abi.encodePacked(to)`.
to := shr(mul(lt(calldatasize(), 0x20), shl(3, sub(0x20, calldatasize()))), to)
// If `to` is `address(0)`, set it to `msg.sender`.
to := xor(mul(xor(to, caller()), iszero(to)), to)
// Transfers the whole balance to `to`.
if iszero(call(gas(), to, selfbalance(), 0x00, 0x00, 0x00, 0x00)) {
mstore(0x00, 0x651aee10) // `WithdrawAllFailed()`.
revert(0x1c, 0x04)
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"evmVersion": "paris",
"optimizer": {
"enabled": true,
"mode": "3",
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"detectMissingLibraries": false,
"forceEVMLA": false,
"enableEraVMExtensions": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_nftContract","type":"address"},{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_claimSigner","type":"address"},{"internalType":"address","name":"_moderator","type":"address"},{"internalType":"uint256","name":"_ratePerSecond","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CannotWithdrawRewardToken","type":"error"},{"inputs":[],"name":"ClaimsNotEnabled","type":"error"},{"inputs":[],"name":"InvalidNFTContract","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotStakeOwner","type":"error"},{"inputs":[],"name":"NotTokenOwner","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"TokenAlreadyStaked","type":"error"},{"inputs":[],"name":"TokenAlreadyTracked","type":"error"},{"inputs":[],"name":"TokenNotHeld","type":"error"},{"inputs":[],"name":"TokenNotInSet","type":"error"},{"inputs":[],"name":"TokenNotStaked","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"accruedNFTSeconds","type":"uint256"}],"name":"Checkpointed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountClaimed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalClaimed","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"},{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"ClaimsEnabledUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"EmergencyNFTWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"EmergencyTokenWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldModerator","type":"address"},{"indexed":true,"internalType":"address","name":"newModerator","type":"address"}],"name":"ModeratorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"NFTRescued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"},{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"PausedStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"RateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":true,"internalType":"address","name":"newSigner","type":"address"}],"name":"SignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint48","name":"timestamp","type":"uint48"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Unlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint48","name":"stakedDuration","type":"uint48"},{"indexed":false,"internalType":"uint256","name":"totalNFTSeconds","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"CLAIM_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_RATE_PER_SECOND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DN404_UNIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accruedNFTSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],"name":"checkpointBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"currentStakeDuration","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"emergencyWithdrawNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"emergencyWithdrawNFTBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyWithdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getAccruedTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getClaimedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getStakeInfo","outputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint48","name":"stakedAt","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isStaked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastCheckpoint","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moderator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nftContract","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"pendingNFTSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ratePerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"rescueUntrackedNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"rescueUntrackedNFTAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rewardCredits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_claimSigner","type":"address"}],"name":"setClaimSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setClaimsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_moderator","type":"address"}],"name":"setModerator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ratePerSecond","type":"uint256"}],"name":"setRatePerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"stakeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"stakedBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"stakedTokensOf","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"stakerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakes","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint48","name":"stakedAt","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"totalAccruedTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"totalNFTSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasuryAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasuryBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"unstakeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"untrackedDepositor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
9c4d535b000000000000000000000000000000000000000000000000000000000000000001000663e8b5975083e6cfd4f649a9d8282f41b682e9b9f3a2d1908d90ef928a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000516dc288e26b34557f68ea1c1ff13576eff8a1680000000000000000000000004b16703f7b0de03d23fd54606ed5786a59e3f27e000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a00000000000000000000000000000000000000000000000000001cd702e31894
Deployed Bytecode
0x0002000000000002001c000000000002000100000001035500000060031002700000059a0030019d0000059a0330019700000001002001900000001f0000c13d0000008002000039000000400020043f000000040030008c00000d140000413d000000000201043b000000e002200270000005aa0020009c000001190000a13d000005ab0020009c000001670000a13d000005ac0020009c000001e80000213d000005b80020009c000002d70000213d000005be0020009c000005890000213d000005c10020009c000007780000613d000005c20020009c00000d140000c13d000000240030008c0000085a0000813d00000d140000013d0000016004000039000000400040043f0000000002000416000000000002004b00000d140000c13d0000001f023000390000059b022001970000016002200039000000400020043f0000001f0530018f0000059c063001980000016002600039000000310000613d000000000701034f000000007807043c0000000004840436000000000024004b0000002d0000c13d000000000005004b0000003e0000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000e00030008c00000d140000413d000001600200043d0000059d0020009c00000d140000213d000001800100043d000f00000001001d0000059d0010009c00000d140000213d000001a00100043d000e00000001001d0000059d0010009c00000d140000213d000001c00100043d000d00000001001d0000059d0010009c00000d140000213d000001e00100043d000c00000001001d0000059d0010009c00000d140000213d000002000100043d000b00000001001d0000059d0010009c00000d140000213d000a00000002001d000002200100043d000900000001001d0000000001000410000000800010043f0000059e01000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000401043b000000a00040043f000000400100043d000005a00010009c000011200000213d0000004002100039000000400020043f00000013020000390000000002210436000005a1030000410000000000320435000000400500043d000005a00050009c000011200000213d000600000004001d0000004003500039000000400030043f0000000103000039000800000005001d0000000004350436000005a203000041000700000004001d00000000003404350000059a0020009c0000059a02008041000000400220021000000000010104330000059a0010009c0000059a010080410000006001100210000000000121019f00000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f000005a3011001c700008010020000391663165e0000040f000000010020019000000d140000613d00000007020000290000059a0020009c0000059a020080410000004002200210000000080300002900000000030304330000059a0030009c0000059a030080410000006003300210000000000223019f000000000101043b000800000001001d00000000010004140000059a0010009c0000059a01008041000000c001100210000000000121019f000005a3011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000805000029000000c00050043f000000e00010043f000000400200043d0000008003200039000000000400041000000000004304350000006003200039000000060400002900000000004304350000004003200039000000000013043500000020012000390000000000510435000005a40100004100000000001204350000059a0020009c0000059a02008041000000400120021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000121019f000005a5011001c700008010020000391663165e0000040f00000001002001900000000a0200002900000d140000613d000000000101043b000001000010043f000000000002004b000008af0000613d0000000f0000006b000008af0000613d0000000e0000006b000008af0000613d0000000d0000006b000008af0000613d0000000c0000006b000008af0000613d0000000a01000029000001200010043f0000000f01000029000001400010043f000000000100041a000005a6011001970000000e011001af000000000010041b0000000103000039000000000103041a000005a6011001970000000c011001af000000000013041b0000000201000039000000000201041a000005a6022001970000000b022001af000000000021041b00000003030000390000000901000029000000000013041b0000000402000039000000000402041a0000065e0140019700000100011001bf000000000012041b000005a7010000410000000d06000029000000000061041b00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d02000039000005a8040000410000000005000019166316590000040f000000010020019000000d140000613d000000800100043d00000140000004430000016000100443000000a00100043d00000020020000390000018000200443000001a000100443000000c00100043d0000004003000039000001c000300443000001e0001004430000006001000039000000e00300043d000002000010044300000220003004430000008001000039000001000300043d00000240001004430000026000300443000000a001000039000001200300043d0000028000100443000002a000300443000000c001000039000001400300043d000002c000100443000002e000300443000001000020044300000007010000390000012000100443000005a901000041000016640001042e000005d80020009c0000019c0000213d000005ee0020009c000002770000a13d000005ef0020009c000003a00000213d000005f50020009c000006050000213d000005f80020009c000009600000613d000005f90020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000402100370000000000202043b000006060020009c00000d140000213d0000002304200039000000000034004b00000d140000813d0000000404200039000000000141034f000000000101043b000800000001001d000006060010009c00000d140000213d000700240020003d000000080100002900000005011002100000000701100029000000000031004b00000d140000213d000005a701000041000000000101041a0000059d011001970000000002000411000000000012004b000001480000613d0000000201000039000000000101041a0000059d01100197000000000012004b00000bc20000c13d0000061501000041000000000201041a0000000003000410000000000032004b000008000000613d000000000031041b0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000080000006b00000ea00000c13d0000000001000412001c00000001001d0000800201000039000000240300003900000000040004150000001c0440008a00000a490000013d000005c30020009c0000021f0000a13d000005c40020009c000002a60000213d000005ca0020009c000004250000213d000005cd0020009c000007880000613d000005ce0020009c00000d140000c13d000000440030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000402100370000000000202043b000f00000002001d0000059d0020009c00000d140000213d0000002401100370000000000301043b000005a701000041000000000201041a0000000001000411000000000021004b00000aee0000c13d000e00000003001d000d00000002001d0000060d01000041000000000010044300000000010004120000000400100443000000c001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000059d011001970000000f02000029000000000012004b00000cb40000c13d0000062b01000041000000000010043f0000062c010000410000166500010430000005d90020009c000002860000a13d000005da0020009c000003a90000213d000005e00020009c000006150000213d000005e30020009c000009720000613d000005e40020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d000000000010043f0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a000f00000001001d0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000f020000290000060802200198000000000101043b00000d220000613d000f00000002001d000000000101041a000e00000001001d000000000001004b0000000001000019000008960000613d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000000f0210006c0000101b0000413d0000000001000019000008960000613d0000000e012000b900000000022100d90000000e0020006c000008960000613d0000101b0000013d000005ad0020009c000002e20000213d000005b30020009c000005980000213d000005b60020009c0000078d0000613d000005b70020009c00000d140000c13d000000240030008c00000d140000413d0000000401100370000000000101043b000f00000001001d0000059d0010009c00000d140000213d000005a701000041000000000101041a0000000002000411000000000012004b00000aee0000c13d00000603010000410000000c0010043f0000000f01000029000000000010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000611011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000d00000001001d000000000101041a000e00000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000000e0010006c00000d240000a13d0000061201000041000000000010043f0000060f010000410000166500010430000005cf0020009c000003d00000a13d000005d00020009c000005740000213d000005d30020009c000007ae0000613d000005d40020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000301043b000005a701000041000000000101041a0000059d011001970000000002000411000000000012004b000002390000613d0000000201000039000000000101041a0000059d01100197000000000012004b00000bc20000c13d0000061501000041000000000201041a0000000004000410000000000042004b000008000000613d000000000041041b000f00000003001d000000000030043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a0000059d011001980000066c0000613d000e00000001001d166315090000040f0000000f01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000001041b0000000e01000029000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000f02000029166315990000040f000000000001004b000010170000c13d0000065601000041000000000010043f0000062c010000410000166500010430000005fa0020009c000003e70000a13d000005fb0020009c0000062e0000213d000005fe0020009c0000075e0000613d000005ff0020009c00000d140000c13d0000000001000416000000000001004b00000d140000c13d0000065c01000041000000800010043f0000060401000041000016640001042e000005e50020009c0000041a0000a13d000005e60020009c0000063e0000213d000005e90020009c000009a40000613d000005ea0020009c00000d140000c13d00000603010000410000000c0010043f0000000001000411000000000010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000611011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000001041b00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d0200003900000002030000390000064904000041000009e00000013d000005c50020009c0000057b0000213d000005c80020009c000007df0000613d000005c90020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000f00000001001d0000059d0010009c00000d140000213d0000000f01000029166315090000040f0000000f01000029000000000010043f0000000801000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a000000400200043d00000000001204350000059a0020009c0000059a02008041000000400120021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d0200003900000002030000390000060c040000410000000f05000029000009e10000013d000005b90020009c000005ad0000213d000005bc0020009c0000075e0000613d000005bd0020009c00000d140000c13d0000000001000416000000000001004b00000d140000c13d00000001010000390000096d0000013d000005ae0020009c000005f20000213d000005b10020009c000007e60000613d000005b20020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000402100370000000000202043b000006060020009c00000d140000213d0000002304200039000000000034004b00000d140000813d0000000404200039000000000141034f000000000101043b000c00000001001d000006060010009c00000d140000213d000b00240020003d0000000c0100002900000005011002100000000b01100029000000000031004b00000d140000213d0000000c0000006b000009e40000613d000e00000000001d0000000e0100002900000005011002100000000b011000290000000101100367000000000101043b0000059d0010009c00000d140000213d0000059d01100197000f00000001001d000000000010043f0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a000d00000001001d0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d020000290000060802200198000000000101043b000003580000613d000000000101041a000000000001004b000003580000613d000a00000002001d000d00000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000000a0110006c0000000d030000290000101b0000413d00000000023100a9000003430000613d00000000011200d9000000000031004b0000101b0000c13d000d00000002001d0000000f01000029000000000010043f0000000801000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000201041a0000000d03000029000000000032001a0000101b0000413d0000000002320019000000000021041b0000000f01000029000000000010043f0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000d00000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b00000608011001970000000d03000029000000000203041a0000060a02200197000000000112019f000000000013041b0000000f01000029000000000010043f0000000801000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a000000400200043d00000000001204350000059a0020009c0000059a02008041000000400120021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d0200003900000002030000390000060c040000410000000f05000029166316590000040f000000010020019000000d140000613d0000000e020000290000000102200039000e00000002001d0000000c0020006c000003030000413d000009e40000013d000005f00020009c000006470000213d000005f30020009c000009ba0000613d000005f40020009c00000d140000c13d000000240030008c0000085a0000813d00000d140000013d000005db0020009c000006700000213d000005de0020009c000009e60000613d000005df0020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b00000d140000c13d000005a702000041000000000502041a0000000002000411000000000052004b00000aee0000c13d0000000402000039000000000302041a0000065e03300197000000000001004b000001000330c1bf000000000032041b000000800010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000630011001c70000800d0200003900000002030000390000063604000041000009e10000013d000005d50020009c000007520000613d000005d60020009c000007730000613d000005d70020009c00000d140000c13d0000000001000416000000000001004b00000d140000c13d000005a701000041000000000501041a0000000001000411000000000051004b00000aee0000c13d0000000401000039000000000201041a0000065f0220019700000001022001bf000000000021041b0000000101000039000000800010043f0000000001000414000009b20000013d000006000020009c000008b30000613d000006010020009c000009030000613d000006020020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000201041a0000059d002001980000000001000019000008960000613d000f00000002001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d0000000f02000029000000a002200270000000000101043b0000060803200197000000000013004b0000101b0000213d00000000012100490000060801100197000008960000013d000005eb0020009c000008ba0000613d000005ec0020009c000009160000613d000005ed0020009c00000d140000c13d0000000001000416000000000001004b00000d140000c13d00000002010000390000096d0000013d000005cb0020009c000007f40000613d000005cc0020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000301043b0000061501000041000000000201041a0000000004000410000000000042004b000008000000613d000000000041041b0000000401000039000000000101041a000000ff0010019000000bc60000c13d000f00000003001d0000000001000411166315090000040f0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000201043b000000400400043d000e00000004001d0000062001000041000000000014043500000004014000390000000f0300002900000000003104350000059a0040009c0000059a010000410000000001044019000000400110021000000000030004140000059a0030009c0000059a03008041000000c003300210000000000113019f00000621011001c70000059d02200197000d00000002001d1663165e0000040f0000000e0b00002900000060031002700000059a03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000004710000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000046d0000c13d000000000006004b0000047e0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000d160000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000006060010009c000011200000213d0000000100200190000011200000c13d000000400010043f000000200030008c00000d140000413d00000000010b04330000059d0010009c00000d140000213d0000000002000411000000000021004b0000123d0000c13d000006170100004100000000001004430000000d01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000f02000029000000000021043500000000010004100000059d01100197000000240230003900000000001204350000061901000041000000000013043500000000010004110000059d01100197000000040230003900000000001204350000059a0030009c000e00000003001d0000059a010000410000000001034019000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000061a011001c70000000d02000029166316590000040f00000001002001900000125c0000613d0000000e01000029000006060010009c000011200000213d0000000e01000029000000400010043f0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000400200043d000e00000002001d000005a00020009c000011200000213d00000608021001970000000e030000290000004001300039000000400010043f00000000010004110000000001130436000c00000002001d000d00000001001d00000000002104350000000f01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000e0200002900000000020204330000059d02200197000000000101043b000000000301041a0000062203300197000000000223019f0000000d030000290000000003030433000000a0033002100000062303300197000000000232019f000000000021041b0000000001000411000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000201043b0000000f01000029000000000010043f000e00000002001d0000000101200039000d00000001001d000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a000000000001004b000012870000c13d0000000e01000029000000000101041a000b00000001001d000006060010009c000011200000213d0000000b0100002900000001011000390000000e02000029000000000012041b000000000020043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000b011000290000000f02000029000000000021041b0000000e01000029000000000101041a000e00000001001d000000000020043f0000000d01000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000e02000029000000000021041b0000000701000039000000000201041a000000010220003a0000101b0000613d000000000021041b000000400100043d0000000c0200002900000000002104350000059a0010009c0000059a01008041000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d020000390000000303000039000006240400004100000000050004110000000f06000029166316590000040f000000010020019000000d140000613d000000400100043d0000000f0200002900000000002104350000059a0010009c0000059a01008041000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d0200003900000001030000390000062504000041166316590000040f000000010020019000000d140000613d0000000001000412001500000001001d000080020100003900000024030000390000000004000415000000150440008a00000a490000013d000005d10020009c000008040000613d000005d20020009c00000d140000c13d000000240030008c000009050000813d00000d140000013d000005c60020009c000008090000613d000005c70020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000000000010043f0000000501000039000009690000013d000005bf0020009c000008580000613d000005c00020009c00000d140000c13d0000000001000416000000000001004b00000d140000c13d0000000001000412001400000001001d001300a00000003d000080050100003900000044030000390000000004000415000000140440008a000007f00000013d000005b40020009c000008630000613d000005b50020009c00000d140000c13d000000240030008c00000d140000413d0000000401100370000000000101043b0000059d0010009c00000d140000213d000005a702000041000000000202041a0000000003000411000000000023004b00000aee0000c13d000000000001004b00000d270000c13d0000060e01000041000000000010043f0000060f010000410000166500010430000005ba0020009c000008890000613d000005bb0020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000402100370000000000202043b000006060020009c00000d140000213d0000002304200039000000000034004b00000d140000813d0000000404200039000000000141034f000000000101043b000700000001001d000006060010009c00000d140000213d000600240020003d000000070100002900000005011002100000000601100029000000000031004b00000d140000213d0000061501000041000000000201041a0000000003000410000000000032004b000008000000613d000000000031041b0000000001000411166315090000040f0000000001000411166314af0000040f0000060d02000041000000000020044300000000020004120000000400200443000000a0020000390000002400200443000500000001001d00000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000070000006b00000d7d0000c13d0000000701000039000000000201041a000000070220006c0000101b0000413d000000000021041b0000000001000412001200000001001d000080020100003900000024030000390000000004000415000000120440008a00000a490000013d000005af0020009c0000089d0000613d000005b00020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d00000603020000410000000c0020043f000000000010043f0000000c010000390000002002000039000009110000013d000005f60020009c000009fa0000613d000005f70020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d000000000010043f00000008010000390000090e0000013d000005e10020009c00000a500000613d000005e20020009c00000d140000c13d000005a701000041000000000501041a0000000001000411000000000051004b00000aee0000c13d00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d020000390000000303000039000005a8040000410000000006000019166316590000040f000000010020019000000d140000613d000005a701000041000000000001041b0000000001000019000016640001042e000005fc0020009c00000a570000613d000005fd0020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d000000000010043f00000006010000390000090e0000013d000005e70020009c00000abd0000613d000005e80020009c00000d140000c13d0000000001000416000000000001004b00000d140000c13d000000000100041a0000096e0000013d000005f10020009c000007520000613d000005f20020009c00000d140000c13d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000301043b0000061501000041000000000201041a0000000004000410000000000042004b000008000000613d000000000041041b0000000001000411000f00000003001d166315090000040f0000000f01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000301041a0000059d0130019800000be90000c13d0000065701000041000000000010043f0000062c010000410000166500010430000005dc0020009c00000ac80000613d000005dd0020009c00000d140000c13d000000440030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000402100370000000000202043b000e00000002001d0000002401100370000000000101043b000f00000001001d0000059d0010009c00000d140000213d000005a701000041000000000101041a0000059d011001970000000002000411000000000012004b0000068c0000613d0000000201000039000000000101041a0000059d01100197000000000012004b00000bc20000c13d0000061501000041000000000201041a0000000003000410000000000032004b000008000000613d000000000031041b0000000f0000006b000008af0000613d0000000e01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a0000059d0010019800000be50000c13d0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000201043b000000400400043d000d00000004001d0000062001000041000000000014043500000004014000390000000e0300002900000000003104350000059a0040009c0000059a010000410000000001044019000000400110021000000000030004140000059a0030009c0000059a03008041000000c003300210000000000113019f00000621011001c70000059d02200197000c00000002001d1663165e0000040f00000060031002700000059a03300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000d0b0000290000000d05700029000006d90000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000006d50000c13d000000000006004b000006e60000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000010d20000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000006060010009c000011200000213d0000000100200190000011200000c13d000000400010043f000000200030008c00000d140000413d00000000010b04330000059d0010009c00000d140000213d0000000002000410000000000021004b000012410000c13d0000000e01000029000000000010043f0000000a01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000201041a000005a602200197000000000021041b000006170100004100000000001004430000000c01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000e02000029000000000021043500000024013000390000000f0200002900000000002104350000061901000041000000000013043500000000010004100000059d01100197000000040230003900000000001204350000059a0030009c000d00000003001d0000059a010000410000000001034019000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000061a011001c70000000c02000029166316590000040f0000000100200190000012e40000613d0000000d01000029000006060010009c000011200000213d0000000d01000029000000400010043f00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d02000039000000040300003900000626040000410000000e050000290000000f060000290000000007000411166316590000040f000000010020019000000d140000613d0000000001000412001800000001001d000080020100003900000024030000390000000004000415000000180440008a00000a490000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d000000000010043f0000000c010000390000090e0000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000000000010043f0000000501000039000000200010043f00000040020000390000000001000019166316260000040f000000000101041a0000059d02100197000000800020043f000000a0011002700000060801100197000000a00010043f0000065d01000041000016640001042e0000000001000416000000000001004b00000d140000c13d0000000701000039000009120000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000000000010043f0000000501000039000000200010043f00000040020000390000000001000019166316260000040f000000000101041a0000059d0010019800000ac30000013d0000000001000416000000000001004b00000d140000c13d0000000301000039000009120000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000301043b000005a701000041000000000101041a0000000002000411000000000012004b00000aee0000c13d0000000301000039000000000101041a000000800010043f000f00000003001d000000a00030043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000613011001c70000800d0200003900000001030000390000061404000041166316590000040f000000010020019000000d140000613d0000000f010000290000000302000039000000000012041b0000000001000019000016640001042e0000000001000416000000000001004b00000d140000c13d0000001301000039000000800010043f000005a102000041000000a00020043f0000010003000039000000400030043f0000000103000039000000c00030043f000005a204000041000000e00040043f0000062e05000041000001000050043f000000e005000039000001200050043f000001e00010043f000002000020043f000002130000043f0000012001000039000001400010043f000002200030043f000002400040043f000002410000043f0000059e01000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000001600010043f0000000001000410000001800010043f000001a00000043f0000016001000039000001c00010043f000000600100043d000002600010043f000000000001004b00000bca0000c13d000001800100003900000bd40000013d0000000001000416000000000001004b00000d140000c13d0000061f01000041000000800010043f0000060401000041000016640001042e0000000001000416000000000001004b00000d140000c13d0000000001000412001100000001001d001000c00000003d000080050100003900000044030000390000000004000415000000110440008a00000005044002100000060d020000411663163b0000040f0000096e0000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000301043b0000061501000041000000000201041a0000000004000410000000000042004b00000af20000c13d0000065801000041000000000010043f0000060f0100004100001665000104300000000001000416000000000001004b00000d140000c13d000005a7010000410000096d0000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000701043b000000000807041a000006060080009c000011200000213d00000005018002100000003f021000390000061e02200197000000400300043d0000000002230019000e00000003001d000000000032004b00000000030000390000000103004039000006060020009c000011200000213d0000000100300190000011200000c13d000000400020043f0000000e0200002900000000068204360000001f0210018f000000000001004b0000083d0000613d0000000001160019000000000300003100000001033003670000000004060019000000003503043c0000000004540436000000000014004b000008390000c13d000000000002004b000000000008004b00000d2a0000c13d000000400100043d000000200200003900000000022104360000000e03000029000000000303043300000000003204350000004002100039000000000003004b0000084f0000613d0000000004000019000000006506043400000000025204360000000104400039000000000034004b0000084a0000413d00000000021200490000059a0020009c0000059a0200804100000060022002100000059a0010009c0000059a010080410000004001100210000000000112019f000016640001042e000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d166314af0000040f000008960000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000f00000001001d0000059d0010009c00000d140000213d000005a701000041000000000101041a0000000002000411000000000012004b00000aee0000c13d0000000f06000029000000000006004b000008af0000613d000000000200041a00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c7000e00000002001d0000059d052001970000800d0200003900000003030000390000061004000041166316590000040f000000010020019000000d140000613d0000000e01000029000005a6011001970000000f011001af000000000010041b0000000001000019000016640001042e000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d166314af0000040f0000000302000039000000000202041a166314a10000040f000000400200043d00000000001204350000059a0020009c0000059a0200804100000040012002100000061d011001c7000016640001042e000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000f00000001001d0000059d0010009c00000d140000213d000005a701000041000000000101041a0000000002000411000000000012004b00000aee0000c13d0000000f06000029000000000006004b00000c9e0000c13d0000063401000041000000000010043f0000062c0100004100001665000104300000000001000416000000000001004b00000d140000c13d0000000401000039000000000101041a0000ff000010019000000ac30000013d0000000001000416000000000001004b00000d140000c13d000000000100041a0000064d02000041000000800020043f0000059d01100197000000840010043f0000060d01000041000000000010044300000000010004120000000400100443000000c001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b00000000030004140000059d021001970000059a0030009c0000059a03008041000000c0013002100000064e011001c71663165e0000040f00000060031002700000059a03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000008e80000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000008e40000c13d000000000006004b000008f50000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000009550000c13d0000001f0530018f0000059c06300198000000400200043d000000000462001900000d6a0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000008fe0000c13d00000d6a0000013d000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d000000000010043f0000000b01000039000000200010043f00000040020000390000000001000019166316260000040f000000000101041a000000800010043f0000060401000041000016640001042e0000000001000416000000000001004b00000d140000c13d000000000100041a0000064b02000041000000800020043f0000059d01100197000000840010043f0000000001000410000000a40010043f0000060d01000041000000000010044300000000010004120000000400100443000000c001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b00000000030004140000059d021001970000059a0030009c0000059a03008041000000c0013002100000064c011001c71663165e0000040f00000060031002700000059a03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000009460000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000009420000c13d000000000006004b000009530000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000bd90000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c00000d140000413d000000800200043d000000000021043500000040011002100000061d011001c7000016640001042e000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000000000010043f0000000a01000039000000200010043f00000040020000390000000001000019166316260000040f000000000101041a0000059d01100197000000800010043f0000060401000041000016640001042e000000840030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000004402100370000000000202043b000d00000002001d0000002402100370000000000202043b000e00000002001d0000000402100370000000000202043b000c00000002001d0000006402100370000000000202043b000f00000002001d000006060020009c00000d140000213d0000000f020000290000002302200039000000000032004b00000d140000813d0000000f02000029000a00040020003d0000000a01100360000000000101043b000b00000001001d000006060010009c00000d140000213d0000000f010000290000002402100039000900000002001d0000000b01200029000000000031004b00000d140000213d0000061501000041000000000201041a0000000003000410000000000032004b000008000000613d000000000031041b0000000401000039000000000101041a0000ff000010019000000d4d0000c13d0000064801000041000000000010043f0000062c0100004100001665000104300000000001000416000000000001004b00000d140000c13d000005a701000041000000000501041a0000000001000411000000000051004b00000aee0000c13d0000000401000039000000000201041a0000065f02200197000000000021041b000000800000043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000630011001c70000800d0200003900000002030000390000063104000041000009e10000013d00000603010000410000000c0010043f0000000001000411000000000010043f0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000f00000001001d00000000010004140000059a0010009c0000059a01008041000000c00110021000000611011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000f02000029000006500220009a000000000021041b00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d02000039000000020300003900000651040000410000000005000411166316590000040f000000010020019000000d140000613d0000000001000019000016640001042e000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b0000059d0010009c00000d140000213d000000000010043f0000000901000039000000200010043f00000040020000390000000001000019166316260000040f000000000101041a0000060801100197000000800010043f0000060401000041000016640001042e000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000402100370000000000202043b000006060020009c00000d140000213d0000002304200039000000000034004b00000d140000813d0000000404200039000000000141034f000000000101043b000800000001001d000006060010009c00000d140000213d000700240020003d000000080100002900000005011002100000000701100029000000000031004b00000d140000213d0000061501000041000000000201041a0000000003000410000000000032004b000008000000613d000000000031041b0000000401000039000000000101041a000000ff0010019000000bc60000c13d0000000001000411166315090000040f0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000f00000001001d0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000080000006b000011260000c13d0000000701000039000000000201041a000000080020002a0000101b0000413d0000000802200029000000000021041b0000000001000412001b00000001001d0000800201000039000000240300003900000000040004150000001b0440008a000000050440021000000617020000411663163b0000040f0000061502000041000000000012041b0000000001000019000016640001042e0000000001000416000000000001004b00000d140000c13d0000063701000041000000800010043f0000060401000041000016640001042e000000840030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000402100370000000000202043b0000059d0020009c00000d140000213d0000002402100370000000000202043b000f00000002001d0000059d0020009c00000d140000213d0000004402100370000000000202043b000e00000002001d0000006402100370000000000202043b000006060020009c00000d140000213d0000002304200039000000000034004b00000d140000813d0000000404200039000000000141034f000000000101043b000006060010009c00000d140000213d00000000011200190000002401100039000000000031004b00000d140000213d0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000059d011001970000000002000411000000000012004b000010210000c13d0000000401000039000000000101041a000000ff0010019000000bc60000c13d0000000f0000006b00000ab50000613d0000000e01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a0000059d0010019800000ab50000c13d0000000e01000029000000000010043f0000000a01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000201041a000005a6022001970000000f022001af000000000021041b000000400100043d0000065b0200004100000000002104350000059a0010009c0000059a0100804100000040011002100000061d011001c7000016640001042e0000000001000416000000000001004b00000d140000c13d0000000401000039000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f0000060401000041000016640001042e000000240030008c00000d140000413d0000000002000416000000000002004b00000d140000c13d0000000401100370000000000101043b000f00000001001d0000059d0010009c00000d140000213d000005a701000041000000000101041a0000000002000411000000000012004b00000aee0000c13d0000000201000039000000000201041a00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c7000e00000002001d0000059d052001970000800d02000039000000030300003900000635040000410000000f06000029166316590000040f000000010020019000000d140000613d0000000e01000029000005a6011001970000000f011001af0000000202000039000000000012041b0000000001000019000016640001042e0000064a01000041000000000010043f0000060f010000410000166500010430000000000041041b000f00000003001d000000000030043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a0000059d0010019800000be50000c13d0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000201043b000000400400043d000e00000004001d0000062001000041000000000014043500000004014000390000000f0300002900000000003104350000059a0040009c0000059a010000410000000001044019000000400110021000000000030004140000059a0030009c0000059a03008041000000c003300210000000000113019f00000621011001c70000059d02200197000d00000002001d1663165e0000040f0000000e0b00002900000060031002700000059a03300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900000b380000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000b340000c13d000000000006004b00000b450000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000d5f0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000006060010009c000011200000213d0000000100200190000011200000c13d000000400010043f000000200030008c00000d140000413d00000000010b04330000059d0010009c00000d140000213d0000000002000410000000000021004b000012410000c13d0000000f01000029000000000010043f0000000a01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a000e059d0010019c000008af0000613d0000000f01000029000000000010043f0000000a01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000201041a000005a602200197000000000021041b000006170100004100000000001004430000000d01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000f02000029000000000021043500000024013000390000000e0200002900000000002104350000061901000041000000000013043500000000010004100000059d01100197000000040230003900000000001204350000059a0030009c000c00000003001d0000059a010000410000000001034019000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000061a011001c70000000d02000029166316590000040f0000000100200190000012d70000613d0000000c01000029000006060010009c000011200000213d0000000c01000029000000400010043f00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d020000390000000403000039000000000700041100000626040000410000000f050000290000000e06000029166316590000040f000000010020019000000d140000613d0000000001000412001600000001001d000080020100003900000024030000390000000004000415000000160440008a00000a490000013d0000065401000041000000000010043f0000062c0100004100001665000104300000065a01000041000000000010043f0000062c0100004100001665000104300000028003000039000000000200001900000080050000390000000004030019000000005305043400000000033404360000000102200039000000000012004b00000bcd0000413d000000e00140008a0000059a0010009c0000059a0100804100000060011002100000062f011001c7000016640001042e0000001f0530018f0000059c06300198000000400200043d000000000462001900000d6a0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000be00000c13d00000d6a0000013d0000063201000041000000000010043f0000062c0100004100001665000104300000000002000411000000000021004b00000e9c0000c13d000e00000003001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d0000000e02000029000000a002200270000000000301043b000e00000002001d0000060801200197000d00000003001d000000000031004b0000101b0000213d0000000f01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000001041b0000000001000411000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000f02000029166315990000040f000000000001004b000002730000613d0000000701000039000000000201041a000000000002004b0000101b0000613d000000010220008a000000000021041b0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000006170200004100000000002004430000059d01100197000c00000001001d000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000f02000029000000000021043500000000010004110000059d01100197000000240230003900000000001204350000061901000041000000000013043500000000010004100000059d01100197000000040230003900000000001204350000059a0030009c000b00000003001d0000059a010000410000000001034019000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000061a011001c70000000c02000029166316590000040f0000000100200190000012ca0000613d0000000b01000029000006060010009c000011200000213d0000000d020000290000000e0120006a000e06080010019b0000000b01000029000000400010043f0000000001000411166314af0000040f000000400200043d000000200320003900000000001304350000000e0100002900000000001204350000059a0020009c0000059a02008041000000400120021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f00000607011001c70000800d0200003900000003030000390000061b0400004100000000050004110000000f06000029166316590000040f000000010020019000000d140000613d000000400100043d0000000f0200002900000000002104350000059a0010009c0000059a01008041000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d0200003900000001030000390000061c04000041166316590000040f000000010020019000000d140000613d0000000001000412001a00000001001d0000800201000039000000240300003900000000040004150000001a0440008a00000a490000013d0000000101000039000000000201041a00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c7000e00000002001d0000059d052001970000800d0200003900000003030000390000060504000041166316590000040f000000010020019000000d140000613d0000000e01000029000005a6011001970000000f011001af0000000102000039000000000012041b0000000001000019000016640001042e000005a701000041000000000101041a000000140010043f0000000e01000029000000340010043f0000062701000041000000000010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000628011001c7166316590000040f00000060031002700000059a03300197000000200030008c000c00000003001d000000200400003900000000040340190000001f0340018f000000200740019000000cd00000613d000000000401034f0000000005000019000000004604043c0000000005650436000000000075004b00000ccc0000c13d000000000003004b00000cdd0000613d000000000171034f0000000303300210000000000407043300000000043401cf000000000434022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000170435000000000100043d000000010010008c00000000010000390000000101006039000b00000002001d000000000112016f000000010010019000000cfc0000c13d000006170100004100000000001004430000000f01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000010200008a0000000b0220014f000000000101043b000000000001004b000000000100003900000001010060390000000c001001b0000000010220c1bf0000000100200190000010250000c13d000000340000043f000005a701000041000000000201041a000000400100043d0000000e0300002900000000003104350000059a0010009c0000059a01008041000000400110021000000000030004140000059a0030009c0000059a03008041000000c003300210000000000113019f0000060b011001c70000059d062001970000800d0200003900000004030000390000062a040000410000000f050000290000000d07000029166316590000040f0000000100200190000009e40000c13d000000000100001900001665000104300000001f0530018f0000059c06300198000000400200043d000000000462001900000d6a0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000d1d0000c13d00000d6a0000013d0000000001000019000008960000013d0000000d01000029000000000001041b0000000f01000029166315830000040f0000000001000019000016640001042e0000000003000019000c00000006001d000d00000007001d000b00000008001d000000000107041a000000000031004b000010110000a13d000f00000003001d000000000070043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000e0200002900000000020204330000000f03000029000000000023004b0000000d07000029000010110000813d00000005023002100000000c060000290000000002620019000000000101043b0000000001310019000000000101041a000000000012043500000001033000390000000b0030006c00000d2e0000413d000008400000013d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000000e0010006c000010290000a13d0000064701000041000000000010043f0000062c0100004100001665000104300000001f0530018f0000059c06300198000000400200043d000000000462001900000d6a0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000d660000c13d000000000005004b00000d770000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f000000000014043500000060013002100000059a0020009c0000059a020080410000004002200210000000000112019f0000166500010430000b059d0010019b00000000010004110004059d0010019b00000000010004100003059d0010019b0000000002000019000a00000002001d000000050120021000000006011000290000000101100367000000000101043b000f00000001001d000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000201041a0000059d012001980000066c0000613d000e00000002001d0000000002000411000000000021004b00000e9c0000c13d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d0000000e02000029000000a002200270000000000301043b000900000002001d0000060801200197000800000003001d000000000031004b0000101b0000213d0000000f01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000001041b0000000001000411000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000201043b0000000f01000029000000000010043f000e00000002001d0000000101200039000c00000001001d000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000e03000029000000000101043b000000000101041a000000000001004b000002730000613d000000000203041a000000000002004b0000101b0000613d000000000021004b000d00000001001d00000e200000613d000200000002001d000000000030043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d020000290001000100200092000000000101043b0000000e04000029000000000204041a000000010020006c000010110000a13d0000000202000029000000010220008a0000000001120019000000000101041a000200000001001d000000000040043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b00000001011000290000000202000029000000000021041b000000000020043f0000000c01000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000d02000029000000000021041b0000000e03000029000000000103041a000d00000001001d000000000001004b000012560000613d000000000030043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d02000029000000010220008a000000000101043b0000000001210019000000000001041b0000000e01000029000000000021041b0000000f01000029000000000010043f0000000c01000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000001041b000006170100004100000000001004430000000b01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000f02000029000000000021043500000024013000390000000402000029000000000021043500000619010000410000000001130436000c00000001001d0000000401300039000000030200002900000000002104350000059a0030009c000e00000003001d0000059a010000410000000001034019000d00400010021800000000010004140000059a0010009c0000059a01008041000000c0011002100000000d011001af0000061a011001c70000000b02000029166316590000040f0000000100200190000012490000613d0000000e03000029000006060030009c000011200000213d0000000802000029000000090120006a0000060801100197000000400030043f00000005020000290000000c040000290000000000240435000000000013043500000000010004140000059a0010009c0000059a01008041000000c0011002100000000d011001af00000607011001c70000800d0200003900000003030000390000061b0400004100000000050004110000000f06000029166316590000040f000000010020019000000d140000613d000000400100043d0000000f0200002900000000002104350000059a0010009c0000059a01008041000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d0200003900000001030000390000061c04000041166316590000040f000000010020019000000d140000613d0000000a020000290000000102200039000000070020006c00000d830000413d000005e60000013d0000064f01000041000000000010043f0000062c010000410000166500010430000a059d0010019b00000000010004100006059d0010019b0000000002000019000900000002001d000000050120021000000007011000290000000101100367000000000101043b000f00000001001d000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a0000059d011001980000066c0000613d000e00000001001d000000000010043f0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a000d00000001001d0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d020000290000060802200198000000000101043b00000f070000613d000000000101041a000000000001004b00000f070000613d000c00000002001d000d00000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000000c0110006c0000000d030000290000101b0000413d00000000023100a900000ef20000613d00000000011200d9000000000031004b0000101b0000c13d000d00000002001d0000000e01000029000000000010043f0000000801000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000201041a0000000d03000029000000000032001a0000101b0000413d0000000002320019000000000021041b0000000e01000029000000000010043f0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000d00000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b00000608011001970000000d03000029000000000203041a0000060a02200197000000000112019f000000000013041b0000000f01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000001041b0000000e01000029000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000201043b0000000f01000029000000000010043f000d00000002001d0000000101200039000b00000001001d000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d03000029000000000101043b000000000101041a000000000001004b000002730000613d000000000203041a000000000002004b0000101b0000613d000000000021004b000c00000001001d00000f980000613d000500000002001d000000000030043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000c020000290004000100200092000000000101043b0000000d04000029000000000204041a000000040020006c000010110000a13d0000000502000029000000010220008a0000000001120019000000000101041a000500000001001d000000000040043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b00000004011000290000000502000029000000000021041b000000000020043f0000000b01000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000c02000029000000000021041b0000000d03000029000000000103041a000c00000001001d000000000001004b000012560000613d000000000030043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000c02000029000000010220008a000000000101043b0000000001210019000000000001041b0000000d01000029000000000021041b0000000f01000029000000000010043f0000000b01000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000001041b0000000701000039000000000101041a000000000001004b0000101b0000613d000000010110008a0000000702000039000000000012041b000006170100004100000000001004430000000a01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000f02000029000000000021043500000024013000390000000e020000290000000000210435000006190100004100000000001304350000000401300039000000060200002900000000002104350000059a0030009c000d00000003001d0000059a010000410000000001034019000c00400010021800000000010004140000059a0010009c0000059a01008041000000c0011002100000000c011001af0000061a011001c70000000a02000029166316590000040f00000001002001900000126d0000613d0000000d01000029000006060010009c000011200000213d0000000d01000029000000400010043f00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d0200003900000004030000390000062d040000410000000f050000290000000e060000290000000007000411166316590000040f000000010020019000000d140000613d0000000f010000290000000d02000029000000000012043500000000010004140000059a0010009c0000059a01008041000000c0011002100000000c011001af0000060b011001c70000800d0200003900000001030000390000061c04000041166316590000040f000000010020019000000d140000613d00000009020000290000000102200039000000080020006c00000ea40000413d000001600000013d0000065501000041000000000010043f0000003201000039000000040010043f000006210100004100001665000104300000000701000039000000000201041a000000000002004b000010de0000c13d0000065501000041000000000010043f0000001101000039000000040010043f000006210100004100001665000104300000065901000041000000000010043f0000062c0100004100001665000104300000062901000041000000000010043f0000060f0100004100001665000104300000000001000411000000000010043f0000000c01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a0000000d0010006b000012450000c13d0000000b01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000000000101041a0008000c00100073000012690000a13d000000400100043d000000a0021000390000000d03000029000000000032043500000080021000390000000e03000029000000000032043500000060021000390000000c030000290000000000320435000000400210003900000000030004110000000000320435000000a0020000390000000002210436000006370300004100000000003204350000063a0010009c000011200000213d000000c003100039000000400030043f0000059a0020009c0000059a02008041000000400220021000000000010104330000059a0010009c0000059a010080410000006001100210000000000121019f00000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f000005a3011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000e00000001001d0000060d010000410000000000100443000000000100041200000004001004430000008001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000700000001001d0000060d01000041000000000010044300000000010004120000000400100443000000240000044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000600000001001d0000060d010000410000000000100443000000000100041200000004001004430000002001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000500000001001d0000059e01000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000400000001001d0000000001000410000000060010006c000013000000c13d0000000502000029000000040020006b000013000000c13d0000063b01000041000000000010043f00000007010000290000001a0010043f0000000e010000290000003a0010043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000063c011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000700000001001d0000003a0000043f0000000101000039000000000101041a000600000001001d000e059d0010019c000013400000c13d0000064601000041000000000010043f0000062c0100004100001665000104300000001f0530018f0000059c06300198000000400200043d000000000462001900000d6a0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000010d90000c13d00000d6a0000013d000000010220008a000000000021041b0000060d01000041000000000010044300000000010004120000000400100443000000a001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000006170200004100000000002004430000059d01100197000d00000001001d000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000f02000029000000000021043500000024013000390000000e0200002900000000002104350000061901000041000000000013043500000000010004100000059d01100197000000040230003900000000001204350000059a0030009c000c00000003001d0000059a010000410000000001034019000b00400010021800000000010004140000059a0010009c0000059a01008041000000c0011002100000000b011001af0000061a011001c70000000d02000029166316590000040f00000001002001900000127a0000613d0000000c01000029000006060010009c000012a40000a13d0000065501000041000000000010043f0000004101000039000000040010043f000006210100004100001665000104300000000f02000029000b06080020019b000e059d0010019b00000000010004100006059d0010019b00000000010004110005059d0010019b0000000002000019000a00000002001d000000050120021000000007011000290000000101100367000000000201043b000000400300043d000d00000003001d000006200100004100000000001304350000000401300039000f00000002001d00000000002104350000059a0030009c0000059a010000410000000001034019000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f00000621011001c70000000e020000291663165e0000040f0000000d0a00002900000060031002700000059a03300197000000200030008c00000020040000390000000004034019000000200640019000000000056a0019000011550000613d000000000701034f00000000080a0019000000007907043c0000000008980436000000000058004b000011510000c13d0000001f07400190000011620000613d000000000661034f0000000307700210000000000805043300000000087801cf000000000878022f000000000606043b0000010007700089000000000676022f00000000067601cf000000000686019f000000000065043500000001002001900000128b0000613d0000001f01400039000000600210018f0000000001a20019000000000021004b00000000020000390000000102004039000006060010009c000011200000213d0000000100200190000011200000c13d000000400010043f000000200030008c00000d140000413d00000000010a04330000059d0010009c00000d140000213d0000000002000411000000000021004b0000123d0000c13d000006170100004100000000001004430000000e01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b00000d140000613d000000400300043d00000044013000390000000f02000029000000000021043500000024013000390000000602000029000000000021043500000619010000410000000001130436000c00000001001d0000000401300039000000050200002900000000002104350000059a0030009c000d00000003001d0000059a010000410000000001034019000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000061a011001c70000000e02000029166316590000040f0000000100200190000012970000613d0000000d02000029000006060020009c000011200000213d000000400020043f000005a00020009c000011200000213d0000004001200039000000400010043f000000000100041100000000001204350000000b010000290000000c0200002900000000001204350000000f01000029000000000010043f0000000501000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d0200002900000000020204330000059d02200197000000000101043b000000000301041a0000062203300197000000000223019f0000000c030000290000000003030433000000a0033002100000062303300197000000000232019f000000000021041b0000000001000411000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000201043b0000000f01000029000000000010043f000d00000002001d0000000101200039000c00000001001d000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d02000029000000000101043b000000000101041a000000000001004b000012870000c13d000000000102041a000006060010009c000011200000213d000900000001001d0000000101100039000000000012041b000000000020043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b00000009011000290000000f02000029000000000021041b0000000d01000029000000000101041a000d00000001001d000000000020043f0000000c01000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000d02000029000000000021041b000000400100043d0000000b0200002900000000002104350000059a0010009c0000059a01008041000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d020000390000000303000039000006240400004100000000050004110000000f06000029166316590000040f000000010020019000000d140000613d000000400100043d0000000f0200002900000000002104350000059a0010009c0000059a01008041000000400110021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f0000060b011001c70000800d0200003900000001030000390000062504000041166316590000040f000000010020019000000d140000613d0000000a020000290000000102200039000000080020006c0000112e0000413d00000a3d0000013d0000065201000041000000000010043f0000062c0100004100001665000104300000063301000041000000000010043f0000062c0100004100001665000104300000063801000041000000000010043f0000062c01000041000016650001043000000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012510000c13d000012f00000013d0000065501000041000000000010043f0000003101000039000000040010043f0000062101000041000016650001043000000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012640000c13d000012f00000013d0000063901000041000000000010043f0000062c01000041000016650001043000000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012750000c13d000012f00000013d00000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012820000c13d000012f00000013d0000065301000041000000000010043f0000062c0100004100001665000104300000001f0530018f0000059c06300198000000400200043d000000000462001900000d6a0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000012920000c13d00000d6a0000013d00000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b0000129f0000c13d000012f00000013d0000000c01000029000000400010043f00000000010004140000059a0010009c0000059a01008041000000c001100210000005a3011001c70000800d0200003900000004030000390000062d040000410000000f050000290000000e060000290000000007000411166316590000040f000000010020019000000d140000613d0000000f010000290000000c02000029000000000012043500000000010004140000059a0010009c0000059a01008041000000c0011002100000000b011001af0000060b011001c70000800d0200003900000001030000390000061c04000041166316590000040f000000010020019000000d140000613d0000000001000412001700000001001d000080020100003900000024030000390000000004000415000000170440008a00000a490000013d00000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012d20000c13d000012f00000013d00000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012df0000c13d000012f00000013d00000060061002700000001f0460018f0000059c05600198000000400200043d0000000003520019000012f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012ec0000c13d0000059a06600197000000000004004b000012fe0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000600160021000000d780000013d000000400200043d000005a401000041000600000002001d0000000001120436000700000001001d0000060d010000410000000000100443000000000100041200000004001004430000004001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000070200002900000000001204350000060d010000410000000000100443000000000100041200000004001004430000006001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000101043b0000000604000029000000800240003900000000030004100000000000320435000000600240003900000004030000290000000000320435000000400240003900000000001204350000059a0040009c0000059a04008041000000400140021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000121019f000005a5011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b000700000001001d000010b70000013d000000400100043d000500000001001d000006170100004100000000001004430000000e01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000000101043b000000000001004b000013660000c13d0000000b01000029000000400010008c000013c10000613d0000000b01000029000000410010008c000010ce0000c13d0000000f0100002900000064011000390000000101100367000000000101043b000000f801100270000000200010043f000000090100002900000001011003670000004002000039000000001301043c0000000002320436000000800020008c000013610000c13d000013ce0000013d000000050500002900000064025000390000004401500039000000240650003900000004035000390000063d040000410000000000450435000000070400002900000000004304350000004003000039000f00000006001d00000000003604350000000b04000029000000000041043500000660034001980000001f0440018f0000000001320019000000090500002900000001055003670000137f0000613d000000000605034f000000006706043c0000000002720436000000000012004b0000137b0000c13d000000000004004b0000138c0000613d000000000235034f0000000303400210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f000000000021043500000005010000290000059a0010009c0000059a0100804100000040011002100000000b020000290000063e0020009c0000063e020080410000006002200210000000000112019f00000000020004140000059a0020009c0000059a02008041000000c002200210000000000121019f0000063f0110009a0000000e020000291663165e0000040f00000060031002700000059a03300197000000200030008c00000020030080390000001f0430018f00000020053001900000000f03500029000013ab0000613d000000000601034f0000000f07000029000000006806043c0000000007870436000000000037004b000013a70000c13d000000000004004b000013b80000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000f0100002900000000010104330000063d0010009c00000000010000390000000101006039000000000112016f0000000100100190000010ce0000613d000013fc0000013d0000000a0400002900000040014000390000000101100367000000000101043b000000ff031002700000001b03300039000000200030043f00000020034000390000000102300367000000000202043b000000400020043f0000064001100197000000600010043f0000000701000029000000000010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000641011001c700000001020000391663165e0000040f000000010900003900000060031002700000059a03300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf000013e60000613d000000000701034f000000007807043c0000000009890436000000000049004b000013e20000c13d000000010220018f000000000005004b000013f40000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000000001020433000000600000043f0000000502000029000000400020043f000000060110014f0000006001100210000000000013004b000010ce0000a13d0000000d01000029000000010010003a0000101b0000413d0000000001000411000000000010043f0000000c01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d0000000d020000290000000102200039000000000101043b000000000021041b0000000001000411000000000010043f0000000b01000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f000000010020019000000d140000613d000000000101043b0000000c02000029000000000021041b0000060d01000041000000000010044300000000010004120000000400100443000000c001000039000000240010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000616011001c700008005020000391663165e0000040f00000001002001900000149c0000613d000000000301043b000000400100043d000e00000001001d000000000100041a0000000802000029000000600020043f0000000002000411000000400020043f00000060011002100000002c0010043f00000642010000410000000c0010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000643011001c7000d00000003001d0000000002030019166316590000040f000f00000002001d00000060021002700000059a02200197000000200020008c000b00000002001d00000020020080390000001f0320018f0000002002200190000014520000613d000000000401034f0000000005000019000000004604043c0000000005650436000000000025004b0000144e0000c13d000000000003004b0000145f0000613d000000000121034f0000000303300210000000000402043300000000043401cf000000000434022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000120435000000000100043d000000010010008c000000000100003900000001010060390000000f0110017f00000001001001900000147d0000c13d000006170100004100000000001004430000000d01000029000000040010044300000000010004140000059a0010009c0000059a01008041000000c00110021000000618011001c700008002020000391663165e0000040f00000001002001900000149c0000613d000000010200008a0000000f0220014f000000000101043b000000000001004b000000000100003900000001010060390000000b001001b0000000010220c1bf00000001002001900000149d0000c13d000000600000043f0000000e03000029000000400030043f00000020013000390000000c020000290000000000210435000000080100002900000000001304350000059a0030009c0000059a03008041000000400130021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f00000607011001c70000800d02000039000000020300003900000645040000410000000005000411166316590000040f000000010020019000000d140000613d0000000001000412001900000001001d000080020100003900000024030000390000000004000415000000190440008a00000a490000013d000000000001042f0000064401000041000000000010043f0000060f010000410000166500010430000000000301001900000000011200a9000000000003004b000014a80000613d00000000033100d9000000000023004b000014a90000c13d000000000001042d0000065501000041000000000010043f0000001101000039000000040010043f0000062101000041000016650001043000030000000000020000059d01100197000300000001001d000000000010043f0000000801000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f0000000100200190000015000000613d000000000101043b000000000101041a000200000001001d0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f0000000100200190000015000000613d000000000101043b000000000101041a000100000001001d0000000301000029000000000010043f0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f0000000100200190000015000000613d00000001020000290000060802200198000000000101043b000014fe0000613d000000000101041a000000000001004b000014fe0000613d000100000002001d000300000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f0000000100200190000015080000613d000000000101043b000000010210006c00000002040000290000000305000029000015020000413d00000000035200a90000000001430019000014fb0000613d00000000022300d9000000000052004b000015020000c13d000000000041004b000015020000413d000000000001042d0000000201000029000000000001042d000000000100001900001665000104300000065501000041000000000010043f0000001101000039000000040010043f00000621010000410000166500010430000000000001042f00030000000000020000059d01100197000300000001001d000000000010043f0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f00000001002001900000157a0000613d000000000101043b000000000101041a000200000001001d0000000601000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f00000001002001900000157a0000613d00000002020000290000060802200198000000000101043b000015580000613d000000000101041a000000000001004b000015580000613d000100000002001d000200000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000157c0000613d000000000101043b000000010110006c00000002030000290000157d0000413d00000000023100a9000015430000613d00000000011200d9000000000031004b0000157d0000c13d000200000002001d0000000301000029000000000010043f0000000801000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f00000001002001900000157a0000613d000000000101043b000000000201041a0000000203000029000000000032001a0000157d0000413d0000000002320019000000000021041b0000000301000029000000000010043f0000000901000039000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f00000001002001900000157a0000613d000000000101043b000300000001001d0000060901000041000000000010044300000000010004140000059a0010009c0000059a01008041000000c0011002100000059f011001c70000800b020000391663165e0000040f00000001002001900000157c0000613d000000000101043b00000608011001970000000303000029000000000203041a0000060a02200197000000000112019f000000000013041b000000000001042d00000000010000190000166500010430000000000001042f0000065501000041000000000010043f0000001101000039000000040010043f000006210100004100001665000104300001000000000002000005a702000041000000000502041a00000000020004140000059d061001970000059a0020009c0000059a02008041000000c001200210000005a3011001c70000800d020000390000000303000039000005a804000041000100000006001d166316590000040f0000000100200190000015970000613d000005a7010000410000000102000029000000000021041b000000000001042d000000000100001900001665000104300006000000000002000300000002001d000000000020043f000600000001001d0000000101100039000400000001001d000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f0000000100200190000016110000613d0000000603000029000000000101043b000000000101041a000000000001004b0000160f0000613d000000000203041a000000000002004b000016130000613d000000000021004b000500000001001d000015ed0000613d000200000002001d000000000030043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f0000000100200190000016110000613d00000005020000290001000100200092000000000101043b0000000604000029000000000204041a000000010020006c000016190000a13d0000000202000029000000010220008a0000000001120019000000000101041a000200000001001d000000000040043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f0000000100200190000016110000613d000000000101043b00000001011000290000000202000029000000000021041b000000000020043f0000000401000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f0000000100200190000016110000613d000000000101043b0000000502000029000000000021041b0000000603000029000000000103041a000500000001001d000000000001004b0000161f0000613d000000000030043f00000000010004140000059a0010009c0000059a01008041000000c0011002100000060b011001c700008010020000391663165e0000040f0000000100200190000016110000613d0000000502000029000000010220008a000000000101043b0000000001210019000000000001041b0000000601000029000000000021041b0000000301000029000000000010043f0000000401000029000000200010043f00000000010004140000059a0010009c0000059a01008041000000c00110021000000607011001c700008010020000391663165e0000040f0000000100200190000016110000613d000000000101043b000000000001041b0000000101000039000000000001042d0000000001000019000000000001042d000000000100001900001665000104300000065501000041000000000010043f0000001101000039000000040010043f000006210100004100001665000104300000065501000041000000000010043f0000003201000039000000040010043f000006210100004100001665000104300000065501000041000000000010043f0000003101000039000000040010043f00000621010000410000166500010430000000000001042f0000059a0010009c0000059a0100804100000040011002100000059a0020009c0000059a020080410000006002200210000000000112019f00000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f000005a3011001c700008010020000391663165e0000040f0000000100200190000016390000613d000000000101043b000000000001042d0000000001000019000016650001043000000000050100190000000000200443000000050030008c000016490000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b000016410000413d0000059a0030009c0000059a03008041000000600130021000000000020004140000059a0020009c0000059a02008041000000c002200210000000000112019f00000661011001c700000000020500191663165e0000040f0000000100200190000016580000613d000000000101043b000000000001042d000000000001042f0000165c002104210000000102000039000000000001042d0000000002000019000000000001042d00001661002104230000000102000039000000000001042d0000000002000019000000000001042d0000166300000432000016640001042e00001665000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff9a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf426561726973684869626561726e6174696f6e00000000000000000000000000310000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f02000000000000000000000000000000000000a0000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e00000000200000000000000000000000000000200000001000000000000000000000000000000000000000000000000000000000000000000000000007ecebdff00000000000000000000000000000000000000000000000000000000baa51f8500000000000000000000000000000000000000000000000000000000e8fe76d400000000000000000000000000000000000000000000000000000000f7c618c000000000000000000000000000000000000000000000000000000000fed80d4200000000000000000000000000000000000000000000000000000000fed80d4300000000000000000000000000000000000000000000000000000000fee81cf400000000000000000000000000000000000000000000000000000000f7c618c100000000000000000000000000000000000000000000000000000000fdaff82d00000000000000000000000000000000000000000000000000000000f0f4425f00000000000000000000000000000000000000000000000000000000f0f4426000000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000e8fe76d500000000000000000000000000000000000000000000000000000000f04e283e00000000000000000000000000000000000000000000000000000000d5a44f8500000000000000000000000000000000000000000000000000000000e0b5541500000000000000000000000000000000000000000000000000000000e0b5541600000000000000000000000000000000000000000000000000000000e64a21f300000000000000000000000000000000000000000000000000000000d5a44f8600000000000000000000000000000000000000000000000000000000d8ee36cb00000000000000000000000000000000000000000000000000000000d30207d400000000000000000000000000000000000000000000000000000000d30207d500000000000000000000000000000000000000000000000000000000d56d229d00000000000000000000000000000000000000000000000000000000baa51f8600000000000000000000000000000000000000000000000000000000bec92aa1000000000000000000000000000000000000000000000000000000008eff1a9700000000000000000000000000000000000000000000000000000000a7693c8900000000000000000000000000000000000000000000000000000000ab08d4fb00000000000000000000000000000000000000000000000000000000ab08d4fc00000000000000000000000000000000000000000000000000000000ac86e18600000000000000000000000000000000000000000000000000000000a7693c8a00000000000000000000000000000000000000000000000000000000a972985e0000000000000000000000000000000000000000000000000000000099d271a10000000000000000000000000000000000000000000000000000000099d271a200000000000000000000000000000000000000000000000000000000a694fc3a000000000000000000000000000000000000000000000000000000008eff1a9800000000000000000000000000000000000000000000000000000000917bb9980000000000000000000000000000000000000000000000000000000084b0196d000000000000000000000000000000000000000000000000000000008da5cb5a000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000008df40be80000000000000000000000000000000000000000000000000000000084b0196e0000000000000000000000000000000000000000000000000000000088c0771b000000000000000000000000000000000000000000000000000000007ecebe0000000000000000000000000000000000000000000000000000000000817b1cd2000000000000000000000000000000000000000000000000000000008456cb5900000000000000000000000000000000000000000000000000000000313dab1f000000000000000000000000000000000000000000000000000000006548b7ad0000000000000000000000000000000000000000000000000000000074a238420000000000000000000000000000000000000000000000000000000075bba1880000000000000000000000000000000000000000000000000000000075bba189000000000000000000000000000000000000000000000000000000007808184b0000000000000000000000000000000000000000000000000000000074a23843000000000000000000000000000000000000000000000000000000007564a48b000000000000000000000000000000000000000000000000000000006b0509b0000000000000000000000000000000000000000000000000000000006b0509b100000000000000000000000000000000000000000000000000000000715018a6000000000000000000000000000000000000000000000000000000006548b7ae0000000000000000000000000000000000000000000000000000000066fd3aba000000000000000000000000000000000000000000000000000000003f4ba839000000000000000000000000000000000000000000000000000000005c975aba000000000000000000000000000000000000000000000000000000005c975abb0000000000000000000000000000000000000000000000000000000061d027b3000000000000000000000000000000000000000000000000000000003f4ba83a0000000000000000000000000000000000000000000000000000000054d1f13d00000000000000000000000000000000000000000000000000000000313dab20000000000000000000000000000000000000000000000000000000003425677e000000000000000000000000000000000000000000000000000000003874390400000000000000000000000000000000000000000000000000000000187958810000000000000000000000000000000000000000000000000000000025692961000000000000000000000000000000000000000000000000000000002d0335aa000000000000000000000000000000000000000000000000000000002d0335ab000000000000000000000000000000000000000000000000000000002e17de780000000000000000000000000000000000000000000000000000000025692962000000000000000000000000000000000000000000000000000000002b4f585200000000000000000000000000000000000000000000000000000000230f436c00000000000000000000000000000000000000000000000000000000230f436d0000000000000000000000000000000000000000000000000000000024b2341a0000000000000000000000000000000000000000000000000000000018795882000000000000000000000000000000000000000000000000000000001e372dc4000000000000000000000000000000000000000000000000000000000981348100000000000000000000000000000000000000000000000000000000150b7a0100000000000000000000000000000000000000000000000000000000150b7a0200000000000000000000000000000000000000000000000000000000167653910000000000000000000000000000000000000000000000000000000009813482000000000000000000000000000000000000000000000000000000000dee32f7000000000000000000000000000000000000000000000000000000000406aa610000000000000000000000000000000000000000000000000000000004e8690300000000000000000000000000000000000000000000000000000000052dd76900000000000000000000000000000000000000000000000000000000389a75e100000000000000000000000000000000000000200000008000000000000000002d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb000000000000000000000000000000000000000000000000ffffffffffffffff02000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffff796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132ffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000020000000000000000000000000000000000002000000000000000000000000099d35d310c9c945374857b12c5aacd15c228347336e834aede361cb66f176d34310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e000000000000000000000000000000000000000000000000000000007448fbae00000000000000000000000000000000000000040000001c00000000000000004ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a02000000000000000000000000000000000000200000000c0000000000000000000000000000000000000000000000000000000000000000000000006f5e88180200000000000000000000000000000000000040000000800000000000000000b38780ddde1f073d91c150de2696f3f7085883648ba21cc5ef01029cb21d19160000000000000000000000000000000000000000000000929eee149b4bd2126802000002000000000000000000000000000000440000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000023b872dd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000009b99f7b307a6ccb858ed7807c962ea0b671f34f7782a046a180b3fdc2ae70593f27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184200000000000000000000000000000000000000200000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000000000000000000000000000000000021e27c1806e59a400006352211e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffffffff00000000000000000000000000000000000000006e8910ae8080a58abd08134c664ce6d891d2355c172dc66c7a66bb8d9e66a7c9032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a161156f5046a9512d1a5348e2eecb62d47d89de20355eaab322a5b0b64500e5d96b700000000000000000000000000000000a9059cbb00000000000000000000000000000000000000000000000000000000000000440000001000000000000000000000000000000000000000000000000000000000000000000000000090b8ec18c51b56711f920e7b82b227c89cf5776728d779ff7a77da028652cee157e902bb6383b2d40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000005ee2181dfa6de3967e89fb130ac3069014db0115a7909237eb145f41f88386880f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000200000000000000000000000000000000000020000000800000000000000000553d0173aaf3da5fa192882a6593e57e95cbf10b294e2e1d5e60806cbeced462858420e900000000000000000000000000000000000000000000000000000000d79a486e00000000000000000000000000000000000000000000000000000000d92e233d00000000000000000000000000000000000000000000000000000000e30826d778da7d768eb0d53d1cce09ef9a58bde3a4ff7ea2999c64d00924dc49ee055495f1bc14e67db7914a3182a05148748ae5803a9853e5ef1614f7a1ba8e897035f006971d702b7abbc980533b1c7ddd4bca05ce1c208d3348fcaddc770e756688fe00000000000000000000000000000000000000000000000000000000969bf72800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff3f000000000000000000000000000000000000000000000000190100000000000002000000000000000000000000000000000000420000001800000000000000001626ba7e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffff9bffffffffffffffffffffffffffffffffffffff9c0000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000000000640000001c0000000000000000000000000000000000000000000000000000000000000000000000007939f424987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a8baa579f000000000000000000000000000000000000000000000000000000000819bdcd00000000000000000000000000000000000000000000000000000000501c54ac00000000000000000000000000000000000000000000000000000000fa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c920000000000000000000000000000000000000000000000000000000082b42900dd62ed3e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004400000080000000000000000070a08231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000800000000000000000cd79e7ec00000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00dbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d59dc379f0000000000000000000000000000000000000000000000000000000016e9ad8f0000000000000000000000000000000000000000000000000000000082b42900000000000000000000000000000000000000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000055809984000000000000000000000000000000000000000000000000000000002926ef0c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab143c06f8af67e5000000000000000000000000000000000000000000000000000000009e87fac800000000000000000000000000000000000000000000000000000000150b7a020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cd702e318940000000000000000000000000000000000000040000000800000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0020000020000000000000000000000000000000000000000000000000000000000ba523b06cca7fe6b7c96269109e255108c3749e3639398ec698fd3c5aeb5fc
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000516dc288e26b34557f68ea1c1ff13576eff8a1680000000000000000000000004b16703f7b0de03d23fd54606ed5786a59e3f27e000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a00000000000000000000000000000000000000000000000000001cd702e31894
-----Decoded View---------------
Arg [0] : _nftContract (address): 0x516DC288e26b34557f68EA1c1Ff13576Eff8a168
Arg [1] : _rewardToken (address): 0x4B16703f7B0de03D23FD54606ed5786a59E3f27e
Arg [2] : _treasury (address): 0xC8F65219949995DEB1390B60F60855a278a2262A
Arg [3] : _owner (address): 0xC8F65219949995DEB1390B60F60855a278a2262A
Arg [4] : _claimSigner (address): 0xC8F65219949995DEB1390B60F60855a278a2262A
Arg [5] : _moderator (address): 0xC8F65219949995DEB1390B60F60855a278a2262A
Arg [6] : _ratePerSecond (uint256): 31709791983764
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000516dc288e26b34557f68ea1c1ff13576eff8a168
Arg [1] : 0000000000000000000000004b16703f7b0de03d23fd54606ed5786a59e3f27e
Arg [2] : 000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a
Arg [3] : 000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a
Arg [4] : 000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a
Arg [5] : 000000000000000000000000c8f65219949995deb1390b60f60855a278a2262a
Arg [6] : 00000000000000000000000000000000000000000000000000001cd702e31894
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.