Source Code
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
There are no matching entriesUpdate your filters to view other transactions | |||||||||
Loading...
Loading
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:
WorldsEscrow
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 32000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "./modules/Ownable/Ownable.sol";
import "./modules/Upgradeable/Upgradeable.sol";
import "./TransferHelper.sol";
import "./IWorldsEscrow.sol";
import "./IWorldsRental.sol";
import "./IWorlds_ERC721.sol";
import "./WorldsEscrowStorage.sol";
contract WorldsEscrow is Context, ERC165, IWorldsEscrow, Ownable, ReentrancyGuard, Upgradeable {
using SafeCast for uint;
using ECDSA for bytes32;
using EnumerableSet for EnumerableSet.UintSet;
// ======== Admin functions ========
constructor(address _rewardTokenAddress, IWorlds_ERC721 _worlds) {
require(_rewardTokenAddress != address(0), "E0"); // E0: addr err
require(address(_worlds) != address(0), "E0");
WorldsEscrowStorage.layout().rewardTokenAddress = _rewardTokenAddress;
WorldsEscrowStorage.layout().Worlds_ERC721 = _worlds;
}
// Set a rewards schedule
// rate is in wei per second for all users
// This must be called AFTER some worlds are staked (or ensure at least 1 world is staked before the start timestamp)
function setRewards(uint32 _start, uint32 _end, uint96 _rate) external onlyOwner checkForUpgrade {
require(_start <= _end, "E1"); // E1: Incorrect input
// some safeguard, value TBD. (2b over 5 years is 12.68 per sec)
require(_rate > 0.03 ether && _rate < 30 ether, "E2"); // E2: Rate incorrect
require(WorldsEscrowStorage.layout().rewardTokenAddress != address(0), "E3"); // E3: Rewards token not set
require(block.timestamp.toUint32() < WorldsEscrowStorage.layout().rewardsPeriod.start || block.timestamp.toUint32() > WorldsEscrowStorage.layout().rewardsPeriod.end, "E4"); // E4: Rewards already set
WorldsEscrowStorage.layout().rewardsPeriod.start = _start;
WorldsEscrowStorage.layout().rewardsPeriod.end = _end;
WorldsEscrowStorage.layout().rewardsPerWeight.lastUpdated = _start;
WorldsEscrowStorage.layout().rewardsPerWeight.rate = _rate;
emit RewardsSet(_start, _end, _rate);
}
function setWeight(uint[] calldata _tokenIds, uint[] calldata _weights) external onlyOwner checkForUpgrade {
require(_tokenIds.length == _weights.length, "E6");
for (uint i = 0; i < _tokenIds.length; i++) {
uint tokenId = _tokenIds[i];
require(WorldsEscrowStorage.layout().worldInfo[tokenId].weight == 0, "E8");
WorldsEscrowStorage.layout().worldInfo[tokenId].weight = _weights[i].toUint16();
}
}
function setSigner(address _signer) external onlyOwner checkForUpgrade {
WorldsEscrowStorage.layout().signer = _signer;
}
function setRentalContract(IWorldsRental _rental) external onlyOwner checkForUpgrade {
require(_rental.supportsInterface(type(IWorldsRental).interfaceId),"E0");
WorldsEscrowStorage.layout().WorldsRental = _rental;
}
function setRewardTokenAddress(address _rewardTokenAddress) external onlyOwner checkForUpgrade {
WorldsEscrowStorage.layout().rewardTokenAddress = _rewardTokenAddress;
}
function setWorldsERC721(IWorlds_ERC721 _worlds) external onlyOwner checkForUpgrade {
WorldsEscrowStorage.layout().Worlds_ERC721 = _worlds;
}
function setWorldsRental(IWorldsRental _rental) external onlyOwner checkForUpgrade {
WorldsEscrowStorage.layout().WorldsRental = _rental;
}
// ======== Public functions ========
// Stake worlds for a first time. You may optionally stake to a different wallet. Ownership will be transferred to the stakeTo address.
// Initial weights passed as input parameters, which are secured by a dev signature. weight = 40003 - 3 * rank
// When you stake you can set rental conditions for all of them.
// Initialized and uninitialized stake can be mixed into one tx using this method.
// If you set rentalPerDay to 0 and rentableUntil to some time in the future, then anyone can rent for free
// until the rentableUntil timestamp with no way of backing out
function initialStake(
uint[] calldata _tokenIds,
uint[] calldata _weights,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil,
uint32 _maxTimestamp,
bytes calldata _signature
) external nonReentrant checkForUpgrade {
require(uint(_deposit) <= uint(_rentalPerDay) * (uint(_minRentDays) + 1), "ER"); // ER: Rental rate incorrect
// security measure against input length attack
require(_tokenIds.length == _weights.length, "E6"); // E6: Input length mismatch
require(block.timestamp <= _maxTimestamp, "EX"); // EX: Signature expired
// verifying signature here is much cheaper than verifying merkle root
require(_verifySignerSignature(keccak256(
abi.encode(_tokenIds, _weights, _msgSender(), _maxTimestamp, address(this))), _signature), "E7"); // E7: Invalid signature
// ensure stakeTo is EOA or ERC721Receiver to avoid token lockup
_ensureEOAorERC721Receiver(_stakeTo);
require(_stakeTo != address(this), "ES"); // ES: Stake to escrow
uint totalWeights = 0;
for (uint i = 0; i < _tokenIds.length; i++) {
{ // scope to avoid stack too deep errors
uint tokenId = _tokenIds[i];
uint _weight = WorldsEscrowStorage.layout().worldInfo[tokenId].weight;
require(_weight == 0 || _weight == _weights[i], "E8"); // E8: Initialized weight cannot be changed
require(WorldsEscrowStorage.layout().Worlds_ERC721.ownerOf(tokenId) == _msgSender(), "E9"); // E9: Not your world
WorldsEscrowStorage.layout().Worlds_ERC721.safeTransferFrom(_msgSender(), address(this), tokenId);
emit WorldStaked(tokenId, _stakeTo);
}
WorldsEscrowStorage.layout().worldInfo[_tokenIds[i]] = WorldInfo(_weights[i].toUint16(), _stakeTo, _deposit, _rentalPerDay, _minRentDays, _rentableUntil);
WorldsEscrowStorage.layout().userStakes[_stakeTo].add(_tokenIds[i]);
totalWeights += _weights[i];
}
// update rewards
_updateRewardsPerWeight(totalWeights.toUint32(), true);
_updateUserRewards(_stakeTo, totalWeights.toUint32(), true);
}
// subsequent staking does not require dev signature
function stake(
uint[] calldata _tokenIds,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external nonReentrant checkForUpgrade {
require(uint(_deposit) <= uint(_rentalPerDay) * (uint(_minRentDays) + 1), "ER"); // ER: Rental rate incorrect
// ensure stakeTo is EOA or ERC721Receiver to avoid token lockup
_ensureEOAorERC721Receiver(_stakeTo);
require(_stakeTo != address(this), "ES"); // ES: Stake to escrow
uint totalWeights = 0;
for (uint i = 0; i < _tokenIds.length; i++) {
uint tokenId = _tokenIds[i];
uint16 _weight = WorldsEscrowStorage.layout().worldInfo[tokenId].weight;
require(_weight != 0, "EA"); // EA: Weight not initialized
require(WorldsEscrowStorage.layout().Worlds_ERC721.ownerOf(tokenId) == _msgSender(), "E9"); // E9: Not your world
WorldsEscrowStorage.layout().Worlds_ERC721.safeTransferFrom(_msgSender(), address(this), tokenId);
totalWeights += _weight;
WorldsEscrowStorage.layout().worldInfo[tokenId] = WorldInfo(_weight, _stakeTo, _deposit, _rentalPerDay, _minRentDays, _rentableUntil);
WorldsEscrowStorage.layout().userStakes[_stakeTo].add(tokenId);
emit WorldStaked(tokenId, _stakeTo);
}
// update rewards
_updateRewardsPerWeight(totalWeights.toUint32(), true);
_updateUserRewards(_stakeTo, totalWeights.toUint32(), true);
}
// Update rental conditions as long as therer's no ongoing rent.
// setting rentableUntil to 0 makes the world unrentable.
function updateRent(
uint[] calldata _tokenIds,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external checkForUpgrade {
require(uint(_deposit) <= uint(_rentalPerDay) * (uint(_minRentDays) + 1), "ER"); // ER: Rental rate incorrect
for (uint i = 0; i < _tokenIds.length; i++) {
uint tokenId = _tokenIds[i];
WorldInfo storage worldInfo_ = WorldsEscrowStorage.layout().worldInfo[tokenId];
require(worldInfo_.weight != 0, "EA"); // EA: Weight not initialized
require(WorldsEscrowStorage.layout().Worlds_ERC721.ownerOf(tokenId) == address(this) && worldInfo_.owner == _msgSender(), "E9"); // E9: Not your world
require(!WorldsEscrowStorage.layout().WorldsRental.isRentActive(tokenId), "EB"); // EB: Ongoing rent
worldInfo_.deposit = _deposit;
worldInfo_.rentalPerDay = _rentalPerDay;
worldInfo_.minRentDays = _minRentDays;
worldInfo_.rentableUntil = _rentableUntil;
}
}
// Extend rental period of ongoing rent
function extendRentalPeriod(uint _tokenId, uint32 _rentableUntil) external checkForUpgrade {
WorldInfo storage worldInfo_ = WorldsEscrowStorage.layout().worldInfo[_tokenId];
require(worldInfo_.weight != 0, "EA"); // EA: Weight not initialized
require(WorldsEscrowStorage.layout().Worlds_ERC721.ownerOf(_tokenId) == address(this) && worldInfo_.owner == _msgSender(), "E9"); // E9: Not your world
worldInfo_.rentableUntil = _rentableUntil;
}
function unstake(uint[] calldata _tokenIds, address _unstakeTo) external nonReentrant checkForUpgrade {
// ensure unstakeTo is EOA or ERC721Receiver to avoid token lockup
_ensureEOAorERC721Receiver(_unstakeTo);
require(_unstakeTo != address(this), "ES"); // ES: Unstake to escrow
uint totalWeights = 0;
for (uint i = 0; i < _tokenIds.length; i++) {
uint tokenId = _tokenIds[i];
require(WorldsEscrowStorage.layout().worldInfo[tokenId].owner == _msgSender(), "E9"); // E9: Not your world
require(!WorldsEscrowStorage.layout().WorldsRental.isRentActive(tokenId), "EB"); // EB: Ongoing rent
WorldsEscrowStorage.layout().Worlds_ERC721.safeTransferFrom(address(this), _unstakeTo, tokenId);
uint16 _weight = WorldsEscrowStorage.layout().worldInfo[tokenId].weight;
totalWeights += _weight;
WorldsEscrowStorage.layout().worldInfo[tokenId] = WorldInfo(_weight,address(0),0,0,0,0);
WorldsEscrowStorage.layout().userStakes[_msgSender()].remove(tokenId);
emit WorldUnstaked(tokenId, _msgSender()); // World `id` unstaked from `address`
}
// update rewards
_updateRewardsPerWeight(totalWeights.toUint32(), false);
_updateUserRewards(_msgSender(), totalWeights.toUint32(), false);
}
function updateWorld(
uint256 _tokenId,
string calldata _ipfsHash,
uint256 _nonce,
bytes calldata _updateApproverSignature
) external checkForUpgrade {
require((WorldsEscrowStorage.layout().worldInfo[_tokenId].owner == _msgSender() && !WorldsEscrowStorage.layout().WorldsRental.isRentActive(_tokenId))
|| (WorldsEscrowStorage.layout().worldInfo[_tokenId].owner != address(0) && WorldsEscrowStorage.layout().WorldsRental.getTenant(_tokenId) == _msgSender()),
"EH"); // EH: Not your world or not rented
WorldsEscrowStorage.layout().Worlds_ERC721.updateWorld(_tokenId, _ipfsHash, _nonce, _updateApproverSignature);
}
// Claim all rewards from caller into a given address
function claim(address _to) external nonReentrant checkForUpgrade {
_updateRewardsPerWeight(0, false);
uint rewardAmount = _updateUserRewards(_msgSender(), 0, false);
WorldsEscrowStorage.layout().rewards[_msgSender()].accumulated = 0;
TransferHelper.safeTransfer(WorldsEscrowStorage.layout().rewardTokenAddress, _to, rewardAmount);
emit RewardClaimed(_to, rewardAmount);
}
// ======== View only functions ========
function getWorldInfo(uint _tokenId) external view override returns(WorldInfo memory) {
return WorldsEscrowStorage.layout().worldInfo[_tokenId];
}
function checkUserRewards(address _user) external view returns(uint) {
RewardsPerWeight memory rewardsPerWeight_ = WorldsEscrowStorage.layout().rewardsPerWeight;
UserRewards memory userRewards_ = WorldsEscrowStorage.layout().rewards[_user];
// Find out the unaccounted time
uint32 end = min(block.timestamp.toUint32(), WorldsEscrowStorage.layout().rewardsPeriod.end);
uint256 unaccountedTime = end - rewardsPerWeight_.lastUpdated; // Cast to uint256 to avoid overflows later on
if (unaccountedTime != 0) {
// Calculate and update the new value of the accumulator. unaccountedTime casts it into uint256, which is desired.
// If the first mint happens mid-program, we don't update the accumulator, no one gets the rewards for that period.
if (rewardsPerWeight_.totalWeight != 0) {
rewardsPerWeight_.accumulated = (rewardsPerWeight_.accumulated + unaccountedTime * rewardsPerWeight_.rate / rewardsPerWeight_.totalWeight).toUint96();
}
}
// Calculate and update the new value user reserves. userRewards_.stakedWeight casts it into uint256, which is desired.
return userRewards_.accumulated + userRewards_.stakedWeight * (rewardsPerWeight_.accumulated - userRewards_.checkpoint);
}
function rewardsPeriod() external view returns (IWorldsEscrow.RewardsPeriod memory) {
return WorldsEscrowStorage.layout().rewardsPeriod;
}
function rewardsPerWeight() external view returns (IWorldsEscrow.RewardsPerWeight memory) {
return WorldsEscrowStorage.layout().rewardsPerWeight;
}
function rewards(address user) external view returns (UserRewards memory) {
return WorldsEscrowStorage.layout().rewards[user];
}
function userStakedWorlds(address _user) external view returns (uint256[] memory) {
uint256 length = WorldsEscrowStorage.layout().userStakes[_user].length();
uint256[] memory stakedWorlds = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
stakedWorlds[i] = WorldsEscrowStorage.layout().userStakes[_user].at(i);
}
return stakedWorlds;
}
function supportsInterface(bytes4 _interfaceId) public view override(ERC165, IERC165) returns (bool) {
return _interfaceId == type(IWorldsEscrow).interfaceId || super.supportsInterface(_interfaceId);
}
// ======== internal functions ========
function _verifySignerSignature(bytes32 _hash, bytes calldata _signature) internal view returns(bool) {
return _hash.toEthSignedMessageHash().recover(_signature) == WorldsEscrowStorage.layout().signer;
}
function min(uint32 _x, uint32 _y) internal pure returns (uint32 z) {
z = (_x < _y) ? _x : _y;
}
// Updates the rewards per weight accumulator.
// Needs to be called on each staking/unstaking event.
function _updateRewardsPerWeight(uint32 _weight, bool _increase) internal checkForUpgrade {
RewardsPerWeight memory rewardsPerWeight_ = WorldsEscrowStorage.layout().rewardsPerWeight;
RewardsPeriod memory rewardsPeriod_ = WorldsEscrowStorage.layout().rewardsPeriod;
// We skip the update if the program hasn't started
if (block.timestamp.toUint32() >= rewardsPeriod_.start) {
// Find out the unaccounted time
uint32 end = min(block.timestamp.toUint32(), rewardsPeriod_.end);
uint256 unaccountedTime = end - rewardsPerWeight_.lastUpdated; // Cast to uint256 to avoid overflows later on
if (unaccountedTime != 0) {
// Calculate and update the new value of the accumulator.
// If the first mint happens mid-program, we don't update the accumulator, no one gets the rewards for that period.
if (rewardsPerWeight_.totalWeight != 0) {
rewardsPerWeight_.accumulated = (rewardsPerWeight_.accumulated + unaccountedTime * rewardsPerWeight_.rate / rewardsPerWeight_.totalWeight).toUint96();
}
rewardsPerWeight_.lastUpdated = end;
}
}
if (_increase) {
rewardsPerWeight_.totalWeight += _weight;
} else {
rewardsPerWeight_.totalWeight -= _weight;
}
WorldsEscrowStorage.layout().rewardsPerWeight = rewardsPerWeight_;
emit RewardsPerWeightUpdated(rewardsPerWeight_.accumulated);
}
// Accumulate rewards for an user.
// Needs to be called on each staking/unstaking event.
function _updateUserRewards(address _user, uint32 _weight, bool _increase) internal checkForUpgrade returns (uint96) {
UserRewards memory userRewards_ = WorldsEscrowStorage.layout().rewards[_user];
RewardsPerWeight memory rewardsPerWeight_ = WorldsEscrowStorage.layout().rewardsPerWeight;
// Calculate and update the new value user reserves.
userRewards_.accumulated = userRewards_.accumulated + userRewards_.stakedWeight * (rewardsPerWeight_.accumulated - userRewards_.checkpoint);
userRewards_.checkpoint = rewardsPerWeight_.accumulated;
if (_weight != 0) {
if (_increase) {
userRewards_.stakedWeight += _weight;
} else {
userRewards_.stakedWeight -= _weight;
}
emit WeightUpdated(_user, _increase, _weight, block.timestamp);
}
WorldsEscrowStorage.layout().rewards[_user] = userRewards_;
emit UserRewardsUpdated(_user, userRewards_.accumulated, userRewards_.checkpoint);
return userRewards_.accumulated;
}
function _ensureEOAorERC721Receiver(address _to) internal checkForUpgrade {
uint32 size;
assembly {
size := extcodesize(_to)
}
if (size > 0) {
try IERC721Receiver(_to).onERC721Received(address(this), address(this), 0, "") returns (bytes4 retval) {
require(retval == IERC721Receiver.onERC721Received.selector, "ET"); // ET: neither EOA nor ERC721Receiver
} catch (bytes memory) {
revert("ET"); // ET: neither EOA nor ERC721Receiver
}
}
}
// ======== function overrides ========
// Prevent sending ERC721 tokens directly to this contract
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external view override returns (bytes4) {
from; tokenId; data; // supress solidity warnings
if (operator == address(this)) {
return this.onERC721Received.selector;
}
else {
return 0x00000000;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 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 ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must 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 ERC721
* 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 caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 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
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```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 of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface IWorlds_ERC721 is IERC721 {
function updateWorld(
uint _tokenId,
string calldata _ipfsHash,
uint256 _nonce,
bytes calldata _updateApproverSignature
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IWorldsEscrow is IERC165, IERC721Receiver {
event WeightUpdated(address indexed user, bool increase, uint weight, uint timestamp);
event WorldStaked(uint256 indexed tokenId, address indexed user);
event WorldUnstaked(uint256 indexed tokenId, address indexed user);
event RewardsSet(uint32 start, uint32 end, uint256 rate);
event RewardsUpdated(uint32 start, uint32 end, uint256 rate);
event RewardsPerWeightUpdated(uint256 accumulated);
event UserRewardsUpdated(address user, uint256 userRewards, uint256 paidRewardPerWeight);
event RewardClaimed(address receiver, uint256 claimed);
struct WorldInfo {
uint16 weight; // weight based on rarity
address owner; // staked to, otherwise owner == 0
uint16 deposit; // unit is ether, paid in WRLD. The deposit is deducted from the last payment(s) since the deposit is non-custodial
uint16 rentalPerDay; // unit is ether, paid in WRLD. Total is deposit + rentalPerDay * days
uint16 minRentDays; // must rent for at least min rent days, otherwise deposit is forfeited up to this amount
uint32 rentableUntil; // timestamp in unix epoch
}
struct RewardsPeriod {
uint32 start; // reward start time, in unix epoch
uint32 end; // reward end time, in unix epoch
}
struct RewardsPerWeight {
uint32 totalWeight;
uint96 accumulated;
uint32 lastUpdated;
uint96 rate;
}
struct UserRewards {
uint32 stakedWeight;
uint96 accumulated;
uint96 checkpoint;
}
// view functions
function getWorldInfo(uint _tokenId) external view returns(WorldInfo memory);
function checkUserRewards(address _user) external view returns(uint);
function rewardsPeriod() external view returns (IWorldsEscrow.RewardsPeriod memory);
function rewardsPerWeight() external view returns(RewardsPerWeight memory);
function rewards(address _user) external view returns (UserRewards memory);
function userStakedWorlds(address _user) external view returns (uint256[] memory);
function onERC721Received(address, address, uint256, bytes calldata) external view override returns(bytes4);
// public functions
function initialStake(
uint[] calldata _tokenIds,
uint[] calldata _weights,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil,
uint32 _maxTimestamp,
bytes calldata _signature
) external;
function stake(
uint[] calldata _tokenIds,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external;
function updateRent(
uint[] calldata _tokenIds,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external;
function extendRentalPeriod(uint _tokenId, uint32 _rentableUntil) external;
function unstake(uint[] calldata _tokenIds, address unstakeTo) external;
function claim(address _to) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IWorldsRental is IERC165 {
event WorldRented(uint256 indexed tokenId, address indexed tenant, uint256 payment);
event RentalPaid(uint256 indexed tokenId, address indexed tenant, uint256 payment);
event RentalTerminated(uint256 indexed tokenId, address indexed tenant);
struct WorldRentInfo {
address tenant; // rented to, otherwise tenant == 0
uint32 rentStartTime; // timestamp in unix epoch
uint32 rentalPaid; // total rental paid since the beginning including the deposit
uint32 paymentAlert; // alert time before next rent payment in seconds (used by frontend only)
}
function isRentActive(uint _tokenId) external view returns(bool);
function getTenant(uint _tokenId) external view returns(address);
function rentedByIndex(address _tenant, uint _index) external view returns(uint);
function isRentable(uint _tokenId) external view returns(bool state);
function rentalPaidUntil(uint _tokenId) external view returns(uint paidUntil);
function rentWorld(uint _tokenId, uint32 _paymentAlert, uint32 initialPayment) external;
function payRent(uint _tokenId, uint32 _payment) external;
function terminateRental(uint _tokenId) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Context.sol";
import "./OwnableStorage.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return OwnableStorage.layout().owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = OwnableStorage.layout().owner;
OwnableStorage.layout().owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
library OwnableStorage {
bytes32 private constant STORAGE_SLOT = keccak256("gg.topia.worlds.Ownable");
struct Layout {
address owner;
}
function layout() internal pure returns (Layout storage _layout) {
bytes32 slot = STORAGE_SLOT;
assembly {
_layout.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "../Ownable/Ownable.sol";
import "./UpgradeableStorage.sol";
contract Upgradeable is Ownable {
function setUpgrade(bytes4 _sig, address _target) external onlyOwner {
UpgradeableStorage.layout().upgrades[_sig] = _target;
}
function hasUpgrade(bytes4 _sig) private view returns (bool) {
return UpgradeableStorage.layout().upgrades[_sig] != address(0);
}
function executeUpgrade(bytes4 _sig) private returns (bool) {
address target = UpgradeableStorage.layout().upgrades[_sig];
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), target, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {revert(0, returndatasize())}
default {return (0, returndatasize())}
}
}
modifier checkForUpgrade() {
if (hasUpgrade(msg.sig)) {
executeUpgrade(msg.sig);
} else {
_;
}
}
fallback() external payable {
require(hasUpgrade(msg.sig));
executeUpgrade(msg.sig);
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
library UpgradeableStorage {
bytes32 private constant STORAGE_SLOT = keccak256("gg.topia.worlds.Upgradeable");
struct Layout {
mapping(bytes4 => address) upgrades;
}
function layout() internal pure returns (Layout storage _layout) {
bytes32 slot = STORAGE_SLOT;
assembly {
_layout.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
/**
helper methods for interacting with ERC20 tokens that do not consistently return true/false
with the addition of a transfer function to send eth or an erc20 token
*/
library TransferHelper {
function safeTransfer(address _token, address _to, uint _value) internal {
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(0xa9059cbb, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper: TRANSFER_FAILED");
}
function safeTransferFrom(address _token, address _from, address _to, uint _value) internal {
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(0x23b872dd, _from, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper: TRANSFER_FROM_FAILED");
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import "./IWorlds_ERC721.sol";
import "./IWorldsEscrow.sol";
import "./IWorldsRental.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
library WorldsEscrowStorage {
bytes32 private constant STORAGE_SLOT = keccak256("slot.worlds.escrow");
struct Layout {
address rewardTokenAddress;
IWorlds_ERC721 Worlds_ERC721;
IWorldsRental WorldsRental;
IWorldsEscrow.WorldInfo[10001] worldInfo; // World tokenId is in N [1,10000]
IWorldsEscrow.RewardsPeriod rewardsPeriod;
IWorldsEscrow.RewardsPerWeight rewardsPerWeight;
mapping(address => IWorldsEscrow.UserRewards) rewards;
mapping(address => EnumerableSet.UintSet) userStakes;
address signer;
}
function layout() internal pure returns (Layout storage _layout) {
bytes32 slot = STORAGE_SLOT;
assembly {
_layout.slot := slot
}
}
}{
"optimizer": {
"enabled": true,
"runs": 32000
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_rewardTokenAddress","type":"address"},{"internalType":"contract IWorlds_ERC721","name":"_worlds","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimed","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"accumulated","type":"uint256"}],"name":"RewardsPerWeightUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"start","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"RewardsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"start","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"RewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"userRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidRewardPerWeight","type":"uint256"}],"name":"UserRewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"increase","type":"bool"},{"indexed":false,"internalType":"uint256","name":"weight","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WeightUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"WorldStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"WorldUnstaked","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"checkUserRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"}],"name":"extendRentalPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getWorldInfo","outputs":[{"components":[{"internalType":"uint16","name":"weight","type":"uint16"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint16","name":"deposit","type":"uint16"},{"internalType":"uint16","name":"rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"minRentDays","type":"uint16"},{"internalType":"uint32","name":"rentableUntil","type":"uint32"}],"internalType":"struct IWorldsEscrow.WorldInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_weights","type":"uint256[]"},{"internalType":"address","name":"_stakeTo","type":"address"},{"internalType":"uint16","name":"_deposit","type":"uint16"},{"internalType":"uint16","name":"_rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"_minRentDays","type":"uint16"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"},{"internalType":"uint32","name":"_maxTimestamp","type":"uint32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"initialStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rewards","outputs":[{"components":[{"internalType":"uint32","name":"stakedWeight","type":"uint32"},{"internalType":"uint96","name":"accumulated","type":"uint96"},{"internalType":"uint96","name":"checkpoint","type":"uint96"}],"internalType":"struct IWorldsEscrow.UserRewards","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerWeight","outputs":[{"components":[{"internalType":"uint32","name":"totalWeight","type":"uint32"},{"internalType":"uint96","name":"accumulated","type":"uint96"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"uint96","name":"rate","type":"uint96"}],"internalType":"struct IWorldsEscrow.RewardsPerWeight","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPeriod","outputs":[{"components":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"}],"internalType":"struct IWorldsEscrow.RewardsPeriod","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IWorldsRental","name":"_rental","type":"address"}],"name":"setRentalContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardTokenAddress","type":"address"}],"name":"setRewardTokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_start","type":"uint32"},{"internalType":"uint32","name":"_end","type":"uint32"},{"internalType":"uint96","name":"_rate","type":"uint96"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sig","type":"bytes4"},{"internalType":"address","name":"_target","type":"address"}],"name":"setUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_weights","type":"uint256[]"}],"name":"setWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IWorlds_ERC721","name":"_worlds","type":"address"}],"name":"setWorldsERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IWorldsRental","name":"_rental","type":"address"}],"name":"setWorldsRental","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"address","name":"_stakeTo","type":"address"},{"internalType":"uint16","name":"_deposit","type":"uint16"},{"internalType":"uint16","name":"_rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"_minRentDays","type":"uint16"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"address","name":"_unstakeTo","type":"address"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint16","name":"_deposit","type":"uint16"},{"internalType":"uint16","name":"_rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"_minRentDays","type":"uint16"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"}],"name":"updateRent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_ipfsHash","type":"string"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"bytes","name":"_updateApproverSignature","type":"bytes"}],"name":"updateWorld","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"userStakedWorlds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b506040516200614938038062006149833981016040819052620000349162000228565b6200003f336200013f565b60016000556001600160a01b038216620000855760405162461bcd60e51b8152602060048201526002602482015261045360f41b60448201526064015b60405180910390fd5b6001600160a01b038116620000c25760405162461bcd60e51b8152602060048201526002602482015261045360f41b60448201526064016200007c565b81620000d8620001c760201b620040a31760201c565b60000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508062000115620001c760201b620040a31760201c565b60010180546001600160a01b0319166001600160a01b039290921691909117905550620002679050565b600062000156620001eb60201b620040c71760201c565b546001600160a01b031690508162000179620001eb602090811b620040c717901c565b80546001600160a01b0319166001600160a01b03928316179055604051838216918316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b7f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc690565b6001600160a01b03811681146200022557600080fd5b50565b600080604083850312156200023c57600080fd5b825162000249816200020f565b60208401519092506200025c816200020f565b809150509250929050565b615ed280620002776000396000f3fe6080604052600436106101a55760003560e01c80636e68dbeb116100e15780639ce0a76a1161008a578063d1259f5a11610064578063d1259f5a1461074a578063dbb37abf1461076a578063f2fde38b1461078a578063fc196d08146107aa576101ac565b80639ce0a76a14610676578063a354f39e14610696578063c19b4ccd146106b6576101ac565b80638da5cb5b116100bb5780638da5cb5b146105d45780639a1e9c33146106285780639a6acf2014610656576101ac565b80636e68dbeb1461057f578063715018a61461059f5780637b892e00146105b4576101ac565b8063363315211161014e5780635a63427e116101285780635a63427e146104ff57806364fe85771461051f578063683b22ec1461053f5780636c19e7831461055f576101ac565b806336331521146104925780634669f9c2146104b25780635330c706146104df576101ac565b80631e83409a1161017f5780631e83409a146103d557806326ae2b78146103f55780632cd8d4d714610472576101ac565b806301ffc9a71461024b5780630700037d14610280578063150b7a0214610384576101ac565b366101ac57005b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1661021c57600080fd5b6102496000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b005b34801561025757600080fd5b5061026b610266366004615479565b61091e565b60405190151581526020015b60405180910390f35b34801561028c57600080fd5b5061034661029b3660046154c8565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff9490941684527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a4825292829020825193840183525463ffffffff811684526bffffffffffffffffffffffff64010000000082048116928501929092527001000000000000000000000000000000009004169082015290565b60408051825163ffffffff1681526020808401516bffffffffffffffffffffffff908116918301919091529282015190921690820152606001610277565b34801561039057600080fd5b506103a461039f366004615527565b6109b6565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610277565b3480156103e157600080fd5b506102496103f03660046154c8565b610a09565b34801561040157600080fd5b506040805180820182526000808252602091820152815180830183527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a25463ffffffff8082168084526401000000009092048116928401928352845191825291519091169181019190915201610277565b34801561047e57600080fd5b5061024961048d366004615605565b610bcd565b34801561049e57600080fd5b506102496104ad36600461568a565b611113565b3480156104be57600080fd5b506104d26104cd3660046154c8565b6117c5565b60405161027791906156e1565b3480156104eb57600080fd5b506102496104fa3660046154c8565b6118ef565b34801561050b57600080fd5b5061024961051a3660046154c8565b6119fa565b34801561052b57600080fd5b5061024961053a366004615725565b611bfb565b34801561054b57600080fd5b5061024961055a366004615835565b61250e565b34801561056b57600080fd5b5061024961057a3660046154c8565b6125ac565b34801561058b57600080fd5b5061024961059a36600461586e565b6126b3565b3480156105ab57600080fd5b50610249612969565b3480156105c057600080fd5b506102496105cf36600461589a565b61297d565b3480156105e057600080fd5b507f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc65460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610277565b34801561063457600080fd5b506106486106433660046154c8565b612bbf565b604051908152602001610277565b34801561066257600080fd5b506102496106713660046154c8565b612de4565b34801561068257600080fd5b50610249610691366004615906565b612eeb565b3480156106a257600080fd5b506102496106b1366004615989565b6132e0565b3480156106c257600080fd5b506106d66106d13660046159d6565b6136e6565b6040516102779190600060c08201905061ffff80845116835273ffffffffffffffffffffffffffffffffffffffff60208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525063ffffffff60a08401511660a083015292915050565b34801561075657600080fd5b506102496107653660046154c8565b613821565b34801561077657600080fd5b506102496107853660046159ef565b6138c2565b34801561079657600080fd5b506102496107a53660046154c8565b614009565b3480156107b657600080fd5b50604080516080808201835260008083526020808401829052838501829052606093840191909152835180830185527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a35463ffffffff8082168084526bffffffffffffffffffffffff6401000000008404811685870190815270010000000000000000000000000000000085048416868b019081527401000000000000000000000000000000000000000090950482169589019586528951928352518116958201959095529151169581019590955251169183019190915201610277565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604081205473ffffffffffffffffffffffffffffffffffffffff1636828037600080366000845af43d6000803e808015610919573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082167e1db37c0000000000000000000000000000000000000000000000000000000014806109b057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60003073ffffffffffffffffffffffffffffffffffffffff8716036109fc57507f150b7a0200000000000000000000000000000000000000000000000000000000610a00565b5060005b95945050505050565b610a116140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615610ab057610aaa6000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50610bc0565b610abb600080614144565b6000610ac9336000806144b9565b3360009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a46020526040902080547fffffffffffffffffffffffffffffffff000000000000000000000000ffffffff1690556bffffffffffffffffffffffff169050610b6f7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e5473ffffffffffffffffffffffffffffffffffffffff168383614880565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241910160405180910390a1505b610bca6001600055565b50565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615610c6c57610c666000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b5061110b565b610c7b61ffff83166001615ab6565b610c899061ffff8516615ac9565b8461ffff161115610ce15760405162461bcd60e51b815260206004820152600260248201527f455200000000000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60005b85811015611109576000878783818110610d0057610d00615ae0565b9050602002013590506000610d327f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301826127118110610d4757610d47615ae0565b01805490915061ffff16600003610da05760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b307f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa158015610e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e569190615b0f565b73ffffffffffffffffffffffffffffffffffffffff16148015610e965750805473ffffffffffffffffffffffffffffffffffffffff620100009091041633145b610ee25760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f667345260000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690636673452690602401602060405180830381865afa158015610f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f979190615b2c565b15610fe45760405162461bcd60e51b815260206004820152600260248201527f45420000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b80547fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000061ffff898116919091027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff16919091177801000000000000000000000000000000000000000000000000888316021779ffffffffffffffffffffffffffffffffffffffffffffffffffff167a010000000000000000000000000000000000000000000000000000918716919091027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16177c010000000000000000000000000000000000000000000000000000000063ffffffff861602179055508061110181615b4e565b915050610ce4565b505b505050505050565b61111b6140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff16156111ba576111b46000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b506117b6565b6111c3816149cf565b3073ffffffffffffffffffffffffffffffffffffffff8216036112285760405162461bcd60e51b815260206004820152600260248201527f45530000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6000805b8381101561178b57600085858381811061124857611248615ae0565b9050602002013590506112583390565b73ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d918261271181106112a1576112a1615ae0565b015462010000900473ffffffffffffffffffffffffffffffffffffffff161461130c5760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f667345260000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690636673452690602401602060405180830381865afa15801561139d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c19190615b2c565b1561140e5760405162461bcd60e51b815260206004820152600260248201527f45420000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff868116602483015260448201849052909116906342842e0e90606401600060405180830381600087803b1580156114aa57600080fd5b505af11580156114be573d6000803e3d6000fd5b5050505060006114eb7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b60030182612711811061150057611500615ae0565b015461ffff1690506115128185615ab6565b6040805160c08101825261ffff84168152600060208201819052918101829052606081018290526080810182905260a08101919091529094507f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9183612711811061157e5761157e615ae0565b825191018054602084015160408501516060860151608087015160a09097015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff61ffff9889167a010000000000000000000000000000000000000000000000000000021679ffffffffffffffffffffffffffffffffffffffffffffffffffff9289167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff948a1676010000000000000000000000000000000000000000000002949094167fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff90961662010000027fffffffffffffffffffff0000000000000000000000000000000000000000000090971699909816989098179490941792909216949094179390931792909216929092171790556117488261172e7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b336000908152612717919091016020526040902090614c45565b50604051339083907ffa3da614f910b1404dc8190d3b3592514bbeda644f073679a843be160f262add90600090a35050808061178390615b4e565b91505061122c565b5061179f61179882614c51565b6000614144565b6117b3336117ac83614c51565b60006144b9565b50505b6117c06001600055565b505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a5602052604081206060919061181690614cd1565b905060008167ffffffffffffffff81111561183357611833615b86565b60405190808252806020026020018201604052801561185c578160200160208202803683370190505b50905060005b828110156118e75773ffffffffffffffffffffffffffffffffffffffff851660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a5602052604090206118b89082614cdb565b8282815181106118ca576118ca615ae0565b6020908102919091010152806118df81615b4e565b915050611862565b509392505050565b6118f7614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611994576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b5050565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611a02614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611a9b576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527fa465369100000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015611b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b499190615b2c565b611b955760405162461bcd60e51b815260206004820152600260248201527f45300000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611c036140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611ca257611c9c6000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b506124f6565b611cb161ffff86166001615ab6565b611cbf9061ffff8816615ac9565b8761ffff161115611d125760405162461bcd60e51b815260206004820152600260248201527f45520000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b8a8914611d615760405162461bcd60e51b815260206004820152600260248201527f45360000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b8263ffffffff16421115611db75760405162461bcd60e51b815260206004820152600260248201527f45580000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b611df48c8c8c8c338830604051602001611dd79796959493929190615c00565b604051602081830303815290604052805190602001208383614d89565b611e405760405162461bcd60e51b815260206004820152600260248201527f45370000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b611e49886149cf565b3073ffffffffffffffffffffffffffffffffffffffff891603611eae5760405162461bcd60e51b815260206004820152600260248201527f45530000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6000805b8c8110156124cb5760008e8e83818110611ece57611ece615ae0565b9050602002013590506000611f007f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301826127118110611f1557611f15615ae0565b015461ffff169050801580611f4157508d8d84818110611f3757611f37615ae0565b9050602002013581145b611f8d5760405162461bcd60e51b815260206004820152600260248201527f45380000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b3373ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa158015612035573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120599190615b0f565b73ffffffffffffffffffffffffffffffffffffffff16146120bc5760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e6001015473ffffffffffffffffffffffffffffffffffffffff166342842e0e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015230602482015260448101859052606401600060405180830381600087803b15801561217057600080fd5b505af1158015612184573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8f1692508491507f386d7662103b38221201a01f5f88ff9c8c03246b5349135976c5dec31f07b7ef90600090a350506040518060c001604052806121f98e8e858181106121ed576121ed615ae0565b90506020020135614e2e565b61ffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a61ffff1681526020018961ffff1681526020018861ffff1681526020018763ffffffff1681525061226d7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b6003018f8f8481811061228257612282615ae0565b90506020020135612711811061229a5761229a615ae0565b825191018054602084015160408501516060860151608087015160a09097015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff61ffff9889167a010000000000000000000000000000000000000000000000000000021679ffffffffffffffffffffffffffffffffffffffffffffffffffff9289167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff948a1676010000000000000000000000000000000000000000000002949094167fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff90961662010000027fffffffffffffffffffff0000000000000000000000000000000000000000000090971699909816989098179490941792909216949094179390931792909216929092171790556124928e8e8381811061243457612434615ae0565b905060200201356124627f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b73ffffffffffffffffffffffffffffffffffffffff8d166000908152612717919091016020526040902090614ea8565b508b8b828181106124a5576124a5615ae0565b90506020020135826124b79190615ab6565b9150806124c381615b4e565b915050611eb2565b506124df6124d882614c51565b6001614144565b6124f3896124ec83614c51565b60016144b9565b50505b6125006001600055565b505050505050505050505050565b612516614ce7565b7fffffffff000000000000000000000000000000000000000000000000000000009190911660009081527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d6020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6125b4614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff161561264d576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff161561274c576117c06000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b60007f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9183612711811061278157612781615ae0565b01805490915061ffff166000036127da5760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b307f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa15801561286c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128909190615b0f565b73ffffffffffffffffffffffffffffffffffffffff161480156128d05750805473ffffffffffffffffffffffffffffffffffffffff620100009091041633145b61291c5760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff8416021790555050565b612971614ce7565b61297b6000614eb4565b565b612985614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612a2457612a1e6000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50612bb9565b828114612a735760405162461bcd60e51b815260206004820152600260248201527f45360000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b60005b83811015612bb7576000858583818110612a9257612a92615ae0565b905060200201359050612ac27f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301816127118110612ad757612ad7615ae0565b015461ffff1615612b2a5760405162461bcd60e51b815260206004820152600260248201527f45380000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b612b3f8484848181106121ed576121ed615ae0565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d91826127118110612b7257612b72615ae0565b0180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff929092169190911790555080612baf81615b4e565b915050612a76565b505b50505050565b604080516080810182527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a35463ffffffff80821683526bffffffffffffffffffffffff640100000000808404821660208087019190915270010000000000000000000000000000000080860485168789015274010000000000000000000000000000000000000000909504831660608088019190915273ffffffffffffffffffffffffffffffffffffffff891660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a4835288812089519283018a5254958616825292850484169181019190915293909204169382019390935282612cfe612cc942614c51565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a254640100000000900463ffffffff16614f4a565b90506000836040015182612d129190615c67565b63ffffffff1690508015612d9757835163ffffffff1615612d975783516060850151612d839163ffffffff1690612d57906bffffffffffffffffffffffff1684615ac9565b612d619190615c84565b85602001516bffffffffffffffffffffffff16612d7e9190615ab6565b614f6c565b6bffffffffffffffffffffffff1660208501525b82604001518460200151612dab9190615cbf565b8351612dbd919063ffffffff16615ce4565b8360200151612dcc9190615d14565b6bffffffffffffffffffffffff169695505050505050565b612dec614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612e85576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612f8457610c666000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b337f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d91876127118110612fb857612fb8615ae0565b015462010000900473ffffffffffffffffffffffffffffffffffffffff1614801561309557507f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f667345260000000000000000000000000000000000000000000000000000000081526004810188905273ffffffffffffffffffffffffffffffffffffffff90911690636673452690602401602060405180830381865afa15801561306f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130939190615b2c565b155b806131db575060007f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d918761271181106130d0576130d0615ae0565b015462010000900473ffffffffffffffffffffffffffffffffffffffff16148015906131db57503373ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f55fd83e50000000000000000000000000000000000000000000000000000000081526004810189905273ffffffffffffffffffffffffffffffffffffffff909116906355fd83e590602401602060405180830381865afa15801561319f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131c39190615b0f565b73ffffffffffffffffffffffffffffffffffffffff16145b6132275760405162461bcd60e51b815260206004820152600260248201527f45480000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8f546040517f9ce0a76a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690639ce0a76a906132a690899089908990899089908990600401615d82565b600060405180830381600087803b1580156132c057600080fd5b505af11580156132d4573d6000803e3d6000fd5b50505050505050505050565b6132e8614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff161561338157612bb96000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b8163ffffffff168363ffffffff1611156133dd5760405162461bcd60e51b815260206004820152600260248201527f45310000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b666a94d74f430000816bffffffffffffffffffffffff1611801561341757506801a055690d9db80000816bffffffffffffffffffffffff16105b6134635760405162461bcd60e51b815260206004820152600260248201527f45320000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e5473ffffffffffffffffffffffffffffffffffffffff166134e75760405162461bcd60e51b815260206004820152600260248201527f45330000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a25463ffffffff1661351842614c51565b63ffffffff16108061356657507f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a254640100000000900463ffffffff1661355e42614c51565b63ffffffff16115b6135b25760405162461bcd60e51b815260206004820152600260248201527f45340000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001663ffffffff858116918217640100000000918616918202179092557f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a380546fffffffffffffffffffffffffffffffff16700100000000000000000000000000000000830273ffffffffffffffffffffffffffffffffffffffff1617740100000000000000000000000000000000000000006bffffffffffffffffffffffff8616908102919091179091556040805192835260208301939093528183015290517f95efd8a2a0aa591f48fd9673cf5d13c2150ca7a1fe1cbe438dd3f0ae47064663916060908290030190a1505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9182612711811061374b5761374b615ae0565b6040805160c081018252929091015461ffff808216845273ffffffffffffffffffffffffffffffffffffffff620100008304166020850152760100000000000000000000000000000000000000000000820481169284019290925278010000000000000000000000000000000000000000000000008104821660608401527a0100000000000000000000000000000000000000000000000000008104909116608083015263ffffffff7c01000000000000000000000000000000000000000000000000000000009091041660a082015292915050565b613829614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611b95576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b6138ca6140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613969576139636000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50613fff565b61397861ffff83166001615ab6565b6139869061ffff8516615ac9565b8461ffff1611156139d95760405162461bcd60e51b815260206004820152600260248201527f45520000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6139e2856149cf565b3073ffffffffffffffffffffffffffffffffffffffff861603613a475760405162461bcd60e51b815260206004820152600260248201527f45530000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6000805b87811015613fe2576000898983818110613a6757613a67615ae0565b9050602002013590506000613a997f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301826127118110613aae57613aae615ae0565b015461ffff1690506000819003613b075760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b3373ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa158015613baf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bd39190615b0f565b73ffffffffffffffffffffffffffffffffffffffff1614613c365760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e6001015473ffffffffffffffffffffffffffffffffffffffff166342842e0e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015230602482015260448101859052606401600060405180830381600087803b158015613cea57600080fd5b505af1158015613cfe573d6000803e3d6000fd5b505050508061ffff1684613d129190615ab6565b93506040518060c001604052808261ffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018961ffff1681526020018861ffff1681526020018761ffff1681526020018663ffffffff16815250613d947f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301836127118110613da957613da9615ae0565b825191018054602084015160408501516060860151608087015160a09097015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff61ffff9889167a010000000000000000000000000000000000000000000000000000021679ffffffffffffffffffffffffffffffffffffffffffffffffffff9289167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff948a1676010000000000000000000000000000000000000000000002949094167fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff90961662010000027fffffffffffffffffffff000000000000000000000000000000000000000000009097169990981698909817949094179290921694909417939093179290921692909217179055613f8982613f597f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b73ffffffffffffffffffffffffffffffffffffffff8c166000908152612717919091016020526040902090614ea8565b5060405173ffffffffffffffffffffffffffffffffffffffff8a169083907f386d7662103b38221201a01f5f88ff9c8c03246b5349135976c5dec31f07b7ef90600090a350508080613fda90615b4e565b915050613a4b565b50613fef6124d882614c51565b613ffc866124ec83614c51565b50505b6111096001600055565b614011614ce7565b73ffffffffffffffffffffffffffffffffffffffff811661409a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610cd8565b610bca81614eb4565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b7f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc690565b60026000540361413d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cd8565b6002600055565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff16156141dd576117c06000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b604080516080810182527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a35463ffffffff80821683526401000000008083046bffffffffffffffffffffffff90811660208087019190915270010000000000000000000000000000000085048416868801527401000000000000000000000000000000000000000090940416606085015284518086019095527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a254808316808752919004909116918401919091529091906142b742614c51565b63ffffffff16106143575760006142da6142d042614c51565b8360200151614f4a565b905060008360400151826142ee9190615c67565b63ffffffff169050801561435457835163ffffffff161561434757835160608501516143339163ffffffff1690612d57906bffffffffffffffffffffffff1684615ac9565b6bffffffffffffffffffffffff1660208501525b63ffffffff821660408501525b50505b821561437d57838260000181815161436f9190615dc2565b63ffffffff16905250614399565b838260000181815161438f9190615c67565b63ffffffff169052505b81517f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a3805460208086015160408088015160608901516bffffffffffffffffffffffff908116740100000000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff63ffffffff93841670010000000000000000000000000000000002166fffffffffffffffffffffffffffffffff9290951664010000000081027fffffffffffffffffffffffffffffffff000000000000000000000000000000009098169390991692909217959095179490941691909117929092179092558051928352517faac1802288db8019f8ec43430efc11a152c72473c57d6ddcde3b6dd0c89260679281900390910190a150505050565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604081205473ffffffffffffffffffffffffffffffffffffffff1615614558576145526000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50614879565b73ffffffffffffffffffffffffffffffffffffffff841660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a46020908152604091829020825160608082018552915463ffffffff80821683526401000000008083046bffffffffffffffffffffffff908116858801527001000000000000000000000000000000009384900481168589019081528851608081018a527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a354808616825293840483169881018990529483049093169784019790975274010000000000000000000000000000000000000000900490951692810192909252925190916146679190615cbf565b8251614679919063ffffffff16615ce4565b82602001516146889190615d14565b6bffffffffffffffffffffffff90811660208085019190915282015116604083015263ffffffff8516156147585783156146dc5784826000018181516146ce9190615dc2565b63ffffffff169052506146f8565b84826000018181516146ee9190615c67565b63ffffffff169052505b60408051851515815263ffffffff871660208201524281830152905173ffffffffffffffffffffffffffffffffffffffff8816917fb1de227711aba68cec92891ccaabad9474a3f417d166ca8f57e7d616f467d343919081900360600190a25b73ffffffffffffffffffffffffffffffffffffffff861660008181527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a460209081526040918290208551815483880151858901516bffffffffffffffffffffffff90811670010000000000000000000000000000000081027fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff9290931664010000000081027fffffffffffffffffffffffffffffffff0000000000000000000000000000000090951663ffffffff9096169590951793909317161790925583519485529184019190915282820152517f5b9aaf4cc5141c090a75f8b8a627863eba92df81f0c83c096350da9b79aedd049181900360600190a1506020015190505b9392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916149179190615ddf565b6000604051808303816000865af19150503d8060008114614954576040519150601f19603f3d011682016040523d82523d6000602084013e614959565b606091505b50915091508180156149835750805115806149835750808060200190518101906149839190615b2c565b612bb75760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610cd8565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615614a68576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b803b63ffffffff811615611990576040517f150b7a020000000000000000000000000000000000000000000000000000000081523060048201819052602482015260006044820181905260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff83169063150b7a029060a4016020604051808303816000875af1925050508015614b38575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252614b3591810190615e0e565b60015b614bb4573d808015614b66576040519150601f19603f3d011682016040523d82523d6000602084013e614b6b565b606091505b5060405162461bcd60e51b815260206004820152600260248201527f45540000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a0200000000000000000000000000000000000000000000000000000000146117c05760405162461bcd60e51b815260206004820152600260248201527f45540000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b60006148798383614ff0565b600063ffffffff821115614ccd5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201527f32206269747300000000000000000000000000000000000000000000000000006064820152608401610cd8565b5090565b60006109b0825490565b600061487983836150ea565b33614d267f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc65473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461297b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a654604080516020601f850181900481028201810190925283815260009273ffffffffffffffffffffffffffffffffffffffff1691614e0f91908690869081908401838280828437600092019190915250614e0992508991506151149050565b90615147565b73ffffffffffffffffffffffffffffffffffffffff1614949350505050565b600061ffff821115614ccd5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610cd8565b60006148798383615163565b7f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc6805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008163ffffffff168363ffffffff1610614f655781614879565b5090919050565b60006bffffffffffffffffffffffff821115614ccd5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610cd8565b600081815260018301602052604081205480156150d9576000615014600183615e2b565b855490915060009061502890600190615e2b565b905081811461508d57600086600001828154811061504857615048615ae0565b906000526020600020015490508087600001848154811061506b5761506b615ae0565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061509e5761509e615e3e565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506109b0565b60009150506109b0565b5092915050565b600082600001828154811061510157615101615ae0565b9060005260206000200154905092915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b600080600061515685856151b2565b915091506118e7816151f7565b60008181526001830160205260408120546151aa575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556109b0565b5060006109b0565b60008082516041036151e85760208301516040840151606085015160001a6151dc8782858561535c565b945094505050506151f0565b506000905060025b9250929050565b600081600481111561520b5761520b615e6d565b036152135750565b600181600481111561522757615227615e6d565b036152745760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610cd8565b600281600481111561528857615288615e6d565b036152d55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610cd8565b60038160048111156152e9576152e9615e6d565b03610bca5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610cd8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156153935750600090506003615442565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156153e7573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661543b57600060019250925050615442565b9150600090505b94509492505050565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610bca57600080fd5b60006020828403121561548b57600080fd5b81356148798161544b565b73ffffffffffffffffffffffffffffffffffffffff81168114610bca57600080fd5b80356154c381615496565b919050565b6000602082840312156154da57600080fd5b813561487981615496565b60008083601f8401126154f757600080fd5b50813567ffffffffffffffff81111561550f57600080fd5b6020830191508360208285010111156151f057600080fd5b60008060008060006080868803121561553f57600080fd5b853561554a81615496565b9450602086013561555a81615496565b935060408601359250606086013567ffffffffffffffff81111561557d57600080fd5b615589888289016154e5565b969995985093965092949392505050565b60008083601f8401126155ac57600080fd5b50813567ffffffffffffffff8111156155c457600080fd5b6020830191508360208260051b85010111156151f057600080fd5b803561ffff811681146154c357600080fd5b803563ffffffff811681146154c357600080fd5b60008060008060008060a0878903121561561e57600080fd5b863567ffffffffffffffff81111561563557600080fd5b61564189828a0161559a565b90975095506156549050602088016155df565b9350615662604088016155df565b9250615670606088016155df565b915061567e608088016155f1565b90509295509295509295565b60008060006040848603121561569f57600080fd5b833567ffffffffffffffff8111156156b657600080fd5b6156c28682870161559a565b90945092505060208401356156d681615496565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b81811015615719578351835292840192918401916001016156fd565b50909695505050505050565b6000806000806000806000806000806000806101208d8f03121561574857600080fd5b67ffffffffffffffff8d35111561575e57600080fd5b61576b8e8e358f0161559a565b909c509a5067ffffffffffffffff60208e0135111561578957600080fd5b6157998e60208f01358f0161559a565b909a5098506157aa60408e016154b8565b97506157b860608e016155df565b96506157c660808e016155df565b95506157d460a08e016155df565b94506157e260c08e016155f1565b93506157f060e08e016155f1565b925067ffffffffffffffff6101008e0135111561580c57600080fd5b61581d8e6101008f01358f016154e5565b81935080925050509295989b509295989b509295989b565b6000806040838503121561584857600080fd5b82356158538161544b565b9150602083013561586381615496565b809150509250929050565b6000806040838503121561588157600080fd5b82359150615891602084016155f1565b90509250929050565b600080600080604085870312156158b057600080fd5b843567ffffffffffffffff808211156158c857600080fd5b6158d48883890161559a565b909650945060208701359150808211156158ed57600080fd5b506158fa8782880161559a565b95989497509550505050565b6000806000806000806080878903121561591f57600080fd5b86359550602087013567ffffffffffffffff8082111561593e57600080fd5b61594a8a838b016154e5565b909750955060408901359450606089013591508082111561596a57600080fd5b5061597789828a016154e5565b979a9699509497509295939492505050565b60008060006060848603121561599e57600080fd5b6159a7846155f1565b92506159b5602085016155f1565b915060408401356bffffffffffffffffffffffff811681146156d657600080fd5b6000602082840312156159e857600080fd5b5035919050565b600080600080600080600060c0888a031215615a0a57600080fd5b873567ffffffffffffffff811115615a2157600080fd5b615a2d8a828b0161559a565b9098509650506020880135615a4181615496565b9450615a4f604089016155df565b9350615a5d606089016155df565b9250615a6b608089016155df565b9150615a7960a089016155f1565b905092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156109b0576109b0615a87565b80820281158282048414176109b0576109b0615a87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215615b2157600080fd5b815161487981615496565b600060208284031215615b3e57600080fd5b8151801515811461487957600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b7f57615b7f615a87565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115615be757600080fd5b8260051b80836020870137939093016020019392505050565b60a081526000615c1460a08301898b615bb5565b8281036020840152615c2781888a615bb5565b73ffffffffffffffffffffffffffffffffffffffff968716604085015263ffffffff95909516606084015250509216608090920191909152949350505050565b63ffffffff8281168282160390808211156150e3576150e3615a87565b600082615cba577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6bffffffffffffffffffffffff8281168282160390808211156150e3576150e3615a87565b6bffffffffffffffffffffffff818116838216028082169190828114615d0c57615d0c615a87565b505092915050565b6bffffffffffffffffffffffff8181168382160190808211156150e3576150e3615a87565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b868152608060208201526000615d9c608083018789615d39565b8560408401528281036060840152615db5818587615d39565b9998505050505050505050565b63ffffffff8181168382160190808211156150e3576150e3615a87565b6000825160005b81811015615e005760208186018101518583015201615de6565b506000920191825250919050565b600060208284031215615e2057600080fd5b81516148798161544b565b818103818111156109b0576109b0615a87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212202086abfba87dcf6ea36b2547ac97a3484a03eb7b5407802bfd6e431f878890dc64736f6c63430008120033000000000000000000000000ccccb68e1a848cbdb5b60a974e07aae143ed40c30000000000000000000000008d9710f0e193d3f95c0723eaaf1a81030dc9116d
Deployed Bytecode
0x6080604052600436106101a55760003560e01c80636e68dbeb116100e15780639ce0a76a1161008a578063d1259f5a11610064578063d1259f5a1461074a578063dbb37abf1461076a578063f2fde38b1461078a578063fc196d08146107aa576101ac565b80639ce0a76a14610676578063a354f39e14610696578063c19b4ccd146106b6576101ac565b80638da5cb5b116100bb5780638da5cb5b146105d45780639a1e9c33146106285780639a6acf2014610656576101ac565b80636e68dbeb1461057f578063715018a61461059f5780637b892e00146105b4576101ac565b8063363315211161014e5780635a63427e116101285780635a63427e146104ff57806364fe85771461051f578063683b22ec1461053f5780636c19e7831461055f576101ac565b806336331521146104925780634669f9c2146104b25780635330c706146104df576101ac565b80631e83409a1161017f5780631e83409a146103d557806326ae2b78146103f55780632cd8d4d714610472576101ac565b806301ffc9a71461024b5780630700037d14610280578063150b7a0214610384576101ac565b366101ac57005b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1661021c57600080fd5b6102496000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b005b34801561025757600080fd5b5061026b610266366004615479565b61091e565b60405190151581526020015b60405180910390f35b34801561028c57600080fd5b5061034661029b3660046154c8565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff9490941684527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a4825292829020825193840183525463ffffffff811684526bffffffffffffffffffffffff64010000000082048116928501929092527001000000000000000000000000000000009004169082015290565b60408051825163ffffffff1681526020808401516bffffffffffffffffffffffff908116918301919091529282015190921690820152606001610277565b34801561039057600080fd5b506103a461039f366004615527565b6109b6565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610277565b3480156103e157600080fd5b506102496103f03660046154c8565b610a09565b34801561040157600080fd5b506040805180820182526000808252602091820152815180830183527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a25463ffffffff8082168084526401000000009092048116928401928352845191825291519091169181019190915201610277565b34801561047e57600080fd5b5061024961048d366004615605565b610bcd565b34801561049e57600080fd5b506102496104ad36600461568a565b611113565b3480156104be57600080fd5b506104d26104cd3660046154c8565b6117c5565b60405161027791906156e1565b3480156104eb57600080fd5b506102496104fa3660046154c8565b6118ef565b34801561050b57600080fd5b5061024961051a3660046154c8565b6119fa565b34801561052b57600080fd5b5061024961053a366004615725565b611bfb565b34801561054b57600080fd5b5061024961055a366004615835565b61250e565b34801561056b57600080fd5b5061024961057a3660046154c8565b6125ac565b34801561058b57600080fd5b5061024961059a36600461586e565b6126b3565b3480156105ab57600080fd5b50610249612969565b3480156105c057600080fd5b506102496105cf36600461589a565b61297d565b3480156105e057600080fd5b507f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc65460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610277565b34801561063457600080fd5b506106486106433660046154c8565b612bbf565b604051908152602001610277565b34801561066257600080fd5b506102496106713660046154c8565b612de4565b34801561068257600080fd5b50610249610691366004615906565b612eeb565b3480156106a257600080fd5b506102496106b1366004615989565b6132e0565b3480156106c257600080fd5b506106d66106d13660046159d6565b6136e6565b6040516102779190600060c08201905061ffff80845116835273ffffffffffffffffffffffffffffffffffffffff60208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525063ffffffff60a08401511660a083015292915050565b34801561075657600080fd5b506102496107653660046154c8565b613821565b34801561077657600080fd5b506102496107853660046159ef565b6138c2565b34801561079657600080fd5b506102496107a53660046154c8565b614009565b3480156107b657600080fd5b50604080516080808201835260008083526020808401829052838501829052606093840191909152835180830185527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a35463ffffffff8082168084526bffffffffffffffffffffffff6401000000008404811685870190815270010000000000000000000000000000000085048416868b019081527401000000000000000000000000000000000000000090950482169589019586528951928352518116958201959095529151169581019590955251169183019190915201610277565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604081205473ffffffffffffffffffffffffffffffffffffffff1636828037600080366000845af43d6000803e808015610919573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082167e1db37c0000000000000000000000000000000000000000000000000000000014806109b057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60003073ffffffffffffffffffffffffffffffffffffffff8716036109fc57507f150b7a0200000000000000000000000000000000000000000000000000000000610a00565b5060005b95945050505050565b610a116140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615610ab057610aaa6000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50610bc0565b610abb600080614144565b6000610ac9336000806144b9565b3360009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a46020526040902080547fffffffffffffffffffffffffffffffff000000000000000000000000ffffffff1690556bffffffffffffffffffffffff169050610b6f7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e5473ffffffffffffffffffffffffffffffffffffffff168383614880565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241910160405180910390a1505b610bca6001600055565b50565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615610c6c57610c666000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b5061110b565b610c7b61ffff83166001615ab6565b610c899061ffff8516615ac9565b8461ffff161115610ce15760405162461bcd60e51b815260206004820152600260248201527f455200000000000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60005b85811015611109576000878783818110610d0057610d00615ae0565b9050602002013590506000610d327f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301826127118110610d4757610d47615ae0565b01805490915061ffff16600003610da05760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b307f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa158015610e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e569190615b0f565b73ffffffffffffffffffffffffffffffffffffffff16148015610e965750805473ffffffffffffffffffffffffffffffffffffffff620100009091041633145b610ee25760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f667345260000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690636673452690602401602060405180830381865afa158015610f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f979190615b2c565b15610fe45760405162461bcd60e51b815260206004820152600260248201527f45420000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b80547fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000061ffff898116919091027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff16919091177801000000000000000000000000000000000000000000000000888316021779ffffffffffffffffffffffffffffffffffffffffffffffffffff167a010000000000000000000000000000000000000000000000000000918716919091027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16177c010000000000000000000000000000000000000000000000000000000063ffffffff861602179055508061110181615b4e565b915050610ce4565b505b505050505050565b61111b6140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff16156111ba576111b46000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b506117b6565b6111c3816149cf565b3073ffffffffffffffffffffffffffffffffffffffff8216036112285760405162461bcd60e51b815260206004820152600260248201527f45530000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6000805b8381101561178b57600085858381811061124857611248615ae0565b9050602002013590506112583390565b73ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d918261271181106112a1576112a1615ae0565b015462010000900473ffffffffffffffffffffffffffffffffffffffff161461130c5760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f667345260000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff90911690636673452690602401602060405180830381865afa15801561139d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c19190615b2c565b1561140e5760405162461bcd60e51b815260206004820152600260248201527f45420000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff868116602483015260448201849052909116906342842e0e90606401600060405180830381600087803b1580156114aa57600080fd5b505af11580156114be573d6000803e3d6000fd5b5050505060006114eb7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b60030182612711811061150057611500615ae0565b015461ffff1690506115128185615ab6565b6040805160c08101825261ffff84168152600060208201819052918101829052606081018290526080810182905260a08101919091529094507f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9183612711811061157e5761157e615ae0565b825191018054602084015160408501516060860151608087015160a09097015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff61ffff9889167a010000000000000000000000000000000000000000000000000000021679ffffffffffffffffffffffffffffffffffffffffffffffffffff9289167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff948a1676010000000000000000000000000000000000000000000002949094167fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff90961662010000027fffffffffffffffffffff0000000000000000000000000000000000000000000090971699909816989098179490941792909216949094179390931792909216929092171790556117488261172e7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b336000908152612717919091016020526040902090614c45565b50604051339083907ffa3da614f910b1404dc8190d3b3592514bbeda644f073679a843be160f262add90600090a35050808061178390615b4e565b91505061122c565b5061179f61179882614c51565b6000614144565b6117b3336117ac83614c51565b60006144b9565b50505b6117c06001600055565b505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a5602052604081206060919061181690614cd1565b905060008167ffffffffffffffff81111561183357611833615b86565b60405190808252806020026020018201604052801561185c578160200160208202803683370190505b50905060005b828110156118e75773ffffffffffffffffffffffffffffffffffffffff851660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a5602052604090206118b89082614cdb565b8282815181106118ca576118ca615ae0565b6020908102919091010152806118df81615b4e565b915050611862565b509392505050565b6118f7614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611994576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b5050565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611a02614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611a9b576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527fa465369100000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015611b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b499190615b2c565b611b955760405162461bcd60e51b815260206004820152600260248201527f45300000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611c036140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611ca257611c9c6000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b506124f6565b611cb161ffff86166001615ab6565b611cbf9061ffff8816615ac9565b8761ffff161115611d125760405162461bcd60e51b815260206004820152600260248201527f45520000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b8a8914611d615760405162461bcd60e51b815260206004820152600260248201527f45360000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b8263ffffffff16421115611db75760405162461bcd60e51b815260206004820152600260248201527f45580000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b611df48c8c8c8c338830604051602001611dd79796959493929190615c00565b604051602081830303815290604052805190602001208383614d89565b611e405760405162461bcd60e51b815260206004820152600260248201527f45370000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b611e49886149cf565b3073ffffffffffffffffffffffffffffffffffffffff891603611eae5760405162461bcd60e51b815260206004820152600260248201527f45530000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6000805b8c8110156124cb5760008e8e83818110611ece57611ece615ae0565b9050602002013590506000611f007f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301826127118110611f1557611f15615ae0565b015461ffff169050801580611f4157508d8d84818110611f3757611f37615ae0565b9050602002013581145b611f8d5760405162461bcd60e51b815260206004820152600260248201527f45380000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b3373ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa158015612035573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120599190615b0f565b73ffffffffffffffffffffffffffffffffffffffff16146120bc5760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e6001015473ffffffffffffffffffffffffffffffffffffffff166342842e0e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015230602482015260448101859052606401600060405180830381600087803b15801561217057600080fd5b505af1158015612184573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8f1692508491507f386d7662103b38221201a01f5f88ff9c8c03246b5349135976c5dec31f07b7ef90600090a350506040518060c001604052806121f98e8e858181106121ed576121ed615ae0565b90506020020135614e2e565b61ffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a61ffff1681526020018961ffff1681526020018861ffff1681526020018763ffffffff1681525061226d7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b6003018f8f8481811061228257612282615ae0565b90506020020135612711811061229a5761229a615ae0565b825191018054602084015160408501516060860151608087015160a09097015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff61ffff9889167a010000000000000000000000000000000000000000000000000000021679ffffffffffffffffffffffffffffffffffffffffffffffffffff9289167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff948a1676010000000000000000000000000000000000000000000002949094167fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff90961662010000027fffffffffffffffffffff0000000000000000000000000000000000000000000090971699909816989098179490941792909216949094179390931792909216929092171790556124928e8e8381811061243457612434615ae0565b905060200201356124627f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b73ffffffffffffffffffffffffffffffffffffffff8d166000908152612717919091016020526040902090614ea8565b508b8b828181106124a5576124a5615ae0565b90506020020135826124b79190615ab6565b9150806124c381615b4e565b915050611eb2565b506124df6124d882614c51565b6001614144565b6124f3896124ec83614c51565b60016144b9565b50505b6125006001600055565b505050505050505050505050565b612516614ce7565b7fffffffff000000000000000000000000000000000000000000000000000000009190911660009081527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d6020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6125b4614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff161561264d576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff161561274c576117c06000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b60007f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9183612711811061278157612781615ae0565b01805490915061ffff166000036127da5760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b307f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa15801561286c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128909190615b0f565b73ffffffffffffffffffffffffffffffffffffffff161480156128d05750805473ffffffffffffffffffffffffffffffffffffffff620100009091041633145b61291c5760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff8416021790555050565b612971614ce7565b61297b6000614eb4565b565b612985614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612a2457612a1e6000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50612bb9565b828114612a735760405162461bcd60e51b815260206004820152600260248201527f45360000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b60005b83811015612bb7576000858583818110612a9257612a92615ae0565b905060200201359050612ac27f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301816127118110612ad757612ad7615ae0565b015461ffff1615612b2a5760405162461bcd60e51b815260206004820152600260248201527f45380000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b612b3f8484848181106121ed576121ed615ae0565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d91826127118110612b7257612b72615ae0565b0180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff929092169190911790555080612baf81615b4e565b915050612a76565b505b50505050565b604080516080810182527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a35463ffffffff80821683526bffffffffffffffffffffffff640100000000808404821660208087019190915270010000000000000000000000000000000080860485168789015274010000000000000000000000000000000000000000909504831660608088019190915273ffffffffffffffffffffffffffffffffffffffff891660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a4835288812089519283018a5254958616825292850484169181019190915293909204169382019390935282612cfe612cc942614c51565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a254640100000000900463ffffffff16614f4a565b90506000836040015182612d129190615c67565b63ffffffff1690508015612d9757835163ffffffff1615612d975783516060850151612d839163ffffffff1690612d57906bffffffffffffffffffffffff1684615ac9565b612d619190615c84565b85602001516bffffffffffffffffffffffff16612d7e9190615ab6565b614f6c565b6bffffffffffffffffffffffff1660208501525b82604001518460200151612dab9190615cbf565b8351612dbd919063ffffffff16615ce4565b8360200151612dcc9190615d14565b6bffffffffffffffffffffffff169695505050505050565b612dec614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612e85576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612f8457610c666000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b337f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d91876127118110612fb857612fb8615ae0565b015462010000900473ffffffffffffffffffffffffffffffffffffffff1614801561309557507f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f667345260000000000000000000000000000000000000000000000000000000081526004810188905273ffffffffffffffffffffffffffffffffffffffff90911690636673452690602401602060405180830381865afa15801561306f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130939190615b2c565b155b806131db575060007f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d918761271181106130d0576130d0615ae0565b015462010000900473ffffffffffffffffffffffffffffffffffffffff16148015906131db57503373ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600201546040517f55fd83e50000000000000000000000000000000000000000000000000000000081526004810189905273ffffffffffffffffffffffffffffffffffffffff909116906355fd83e590602401602060405180830381865afa15801561319f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131c39190615b0f565b73ffffffffffffffffffffffffffffffffffffffff16145b6132275760405162461bcd60e51b815260206004820152600260248201527f45480000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8f546040517f9ce0a76a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690639ce0a76a906132a690899089908990899089908990600401615d82565b600060405180830381600087803b1580156132c057600080fd5b505af11580156132d4573d6000803e3d6000fd5b50505050505050505050565b6132e8614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff161561338157612bb96000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b8163ffffffff168363ffffffff1611156133dd5760405162461bcd60e51b815260206004820152600260248201527f45310000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b666a94d74f430000816bffffffffffffffffffffffff1611801561341757506801a055690d9db80000816bffffffffffffffffffffffff16105b6134635760405162461bcd60e51b815260206004820152600260248201527f45320000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e5473ffffffffffffffffffffffffffffffffffffffff166134e75760405162461bcd60e51b815260206004820152600260248201527f45330000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a25463ffffffff1661351842614c51565b63ffffffff16108061356657507f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a254640100000000900463ffffffff1661355e42614c51565b63ffffffff16115b6135b25760405162461bcd60e51b815260206004820152600260248201527f45340000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001663ffffffff858116918217640100000000918616918202179092557f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a380546fffffffffffffffffffffffffffffffff16700100000000000000000000000000000000830273ffffffffffffffffffffffffffffffffffffffff1617740100000000000000000000000000000000000000006bffffffffffffffffffffffff8616908102919091179091556040805192835260208301939093528183015290517f95efd8a2a0aa591f48fd9673cf5d13c2150ca7a1fe1cbe438dd3f0ae47064663916060908290030190a1505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d9182612711811061374b5761374b615ae0565b6040805160c081018252929091015461ffff808216845273ffffffffffffffffffffffffffffffffffffffff620100008304166020850152760100000000000000000000000000000000000000000000820481169284019290925278010000000000000000000000000000000000000000000000008104821660608401527a0100000000000000000000000000000000000000000000000000008104909116608083015263ffffffff7c01000000000000000000000000000000000000000000000000000000009091041660a082015292915050565b613829614ce7565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611b95576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b6138ca6140eb565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613969576139636000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50613fff565b61397861ffff83166001615ab6565b6139869061ffff8516615ac9565b8461ffff1611156139d95760405162461bcd60e51b815260206004820152600260248201527f45520000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6139e2856149cf565b3073ffffffffffffffffffffffffffffffffffffffff861603613a475760405162461bcd60e51b815260206004820152600260248201527f45530000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b6000805b87811015613fe2576000898983818110613a6757613a67615ae0565b9050602002013590506000613a997f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301826127118110613aae57613aae615ae0565b015461ffff1690506000819003613b075760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b3373ffffffffffffffffffffffffffffffffffffffff167f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e600101546040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636352211e90602401602060405180830381865afa158015613baf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bd39190615b0f565b73ffffffffffffffffffffffffffffffffffffffff1614613c365760405162461bcd60e51b815260206004820152600260248201527f45390000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e6001015473ffffffffffffffffffffffffffffffffffffffff166342842e0e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015230602482015260448101859052606401600060405180830381600087803b158015613cea57600080fd5b505af1158015613cfe573d6000803e3d6000fd5b505050508061ffff1684613d129190615ab6565b93506040518060c001604052808261ffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018961ffff1681526020018861ffff1681526020018761ffff1681526020018663ffffffff16815250613d947f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b600301836127118110613da957613da9615ae0565b825191018054602084015160408501516060860151608087015160a09097015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff61ffff9889167a010000000000000000000000000000000000000000000000000000021679ffffffffffffffffffffffffffffffffffffffffffffffffffff9289167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff948a1676010000000000000000000000000000000000000000000002949094167fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff90961662010000027fffffffffffffffffffff000000000000000000000000000000000000000000009097169990981698909817949094179290921694909417939093179290921692909217179055613f8982613f597f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b73ffffffffffffffffffffffffffffffffffffffff8c166000908152612717919091016020526040902090614ea8565b5060405173ffffffffffffffffffffffffffffffffffffffff8a169083907f386d7662103b38221201a01f5f88ff9c8c03246b5349135976c5dec31f07b7ef90600090a350508080613fda90615b4e565b915050613a4b565b50613fef6124d882614c51565b613ffc866124ec83614c51565b50505b6111096001600055565b614011614ce7565b73ffffffffffffffffffffffffffffffffffffffff811661409a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610cd8565b610bca81614eb4565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e3d8e90565b7f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc690565b60026000540361413d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cd8565b6002600055565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff16156141dd576117c06000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b604080516080810182527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a35463ffffffff80821683526401000000008083046bffffffffffffffffffffffff90811660208087019190915270010000000000000000000000000000000085048416868801527401000000000000000000000000000000000000000090940416606085015284518086019095527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a254808316808752919004909116918401919091529091906142b742614c51565b63ffffffff16106143575760006142da6142d042614c51565b8360200151614f4a565b905060008360400151826142ee9190615c67565b63ffffffff169050801561435457835163ffffffff161561434757835160608501516143339163ffffffff1690612d57906bffffffffffffffffffffffff1684615ac9565b6bffffffffffffffffffffffff1660208501525b63ffffffff821660408501525b50505b821561437d57838260000181815161436f9190615dc2565b63ffffffff16905250614399565b838260000181815161438f9190615c67565b63ffffffff169052505b81517f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a3805460208086015160408088015160608901516bffffffffffffffffffffffff908116740100000000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff63ffffffff93841670010000000000000000000000000000000002166fffffffffffffffffffffffffffffffff9290951664010000000081027fffffffffffffffffffffffffffffffff000000000000000000000000000000009098169390991692909217959095179490941691909117929092179092558051928352517faac1802288db8019f8ec43430efc11a152c72473c57d6ddcde3b6dd0c89260679281900390910190a150505050565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604081205473ffffffffffffffffffffffffffffffffffffffff1615614558576145526000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b50614879565b73ffffffffffffffffffffffffffffffffffffffff841660009081527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a46020908152604091829020825160608082018552915463ffffffff80821683526401000000008083046bffffffffffffffffffffffff908116858801527001000000000000000000000000000000009384900481168589019081528851608081018a527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a354808616825293840483169881018990529483049093169784019790975274010000000000000000000000000000000000000000900490951692810192909252925190916146679190615cbf565b8251614679919063ffffffff16615ce4565b82602001516146889190615d14565b6bffffffffffffffffffffffff90811660208085019190915282015116604083015263ffffffff8516156147585783156146dc5784826000018181516146ce9190615dc2565b63ffffffff169052506146f8565b84826000018181516146ee9190615c67565b63ffffffff169052505b60408051851515815263ffffffff871660208201524281830152905173ffffffffffffffffffffffffffffffffffffffff8816917fb1de227711aba68cec92891ccaabad9474a3f417d166ca8f57e7d616f467d343919081900360600190a25b73ffffffffffffffffffffffffffffffffffffffff861660008181527f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a460209081526040918290208551815483880151858901516bffffffffffffffffffffffff90811670010000000000000000000000000000000081027fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff9290931664010000000081027fffffffffffffffffffffffffffffffff0000000000000000000000000000000090951663ffffffff9096169590951793909317161790925583519485529184019190915282820152517f5b9aaf4cc5141c090a75f8b8a627863eba92df81f0c83c096350da9b79aedd049181900360600190a1506020015190505b9392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916149179190615ddf565b6000604051808303816000865af19150503d8060008114614954576040519150601f19603f3d011682016040523d82523d6000602084013e614959565b606091505b50915091508180156149835750805115806149835750808060200190518101906149839190615b2c565b612bb75760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610cd8565b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527f465c35ad1d12a6f76ffabe3e9eca16a7f4fd728d9969a9386eb4f7d2c55ac80d602052604090205473ffffffffffffffffffffffffffffffffffffffff1615614a68576119906000357fffffffff0000000000000000000000000000000000000000000000000000000016610894565b803b63ffffffff811615611990576040517f150b7a020000000000000000000000000000000000000000000000000000000081523060048201819052602482015260006044820181905260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff83169063150b7a029060a4016020604051808303816000875af1925050508015614b38575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252614b3591810190615e0e565b60015b614bb4573d808015614b66576040519150601f19603f3d011682016040523d82523d6000602084013e614b6b565b606091505b5060405162461bcd60e51b815260206004820152600260248201527f45540000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a0200000000000000000000000000000000000000000000000000000000146117c05760405162461bcd60e51b815260206004820152600260248201527f45540000000000000000000000000000000000000000000000000000000000006044820152606401610cd8565b60006148798383614ff0565b600063ffffffff821115614ccd5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201527f32206269747300000000000000000000000000000000000000000000000000006064820152608401610cd8565b5090565b60006109b0825490565b600061487983836150ea565b33614d267f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc65473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461297b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cd8565b7f182f2d10717f147cdc0726110024d37e6af37e0338e42487d6950f1c5e2e64a654604080516020601f850181900481028201810190925283815260009273ffffffffffffffffffffffffffffffffffffffff1691614e0f91908690869081908401838280828437600092019190915250614e0992508991506151149050565b90615147565b73ffffffffffffffffffffffffffffffffffffffff1614949350505050565b600061ffff821115614ccd5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610cd8565b60006148798383615163565b7f2964b7e756c43d7fc626c76da5b94aa9f7f497362e81c25e47dc710c9dbd2bc6805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008163ffffffff168363ffffffff1610614f655781614879565b5090919050565b60006bffffffffffffffffffffffff821115614ccd5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610cd8565b600081815260018301602052604081205480156150d9576000615014600183615e2b565b855490915060009061502890600190615e2b565b905081811461508d57600086600001828154811061504857615048615ae0565b906000526020600020015490508087600001848154811061506b5761506b615ae0565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061509e5761509e615e3e565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506109b0565b60009150506109b0565b5092915050565b600082600001828154811061510157615101615ae0565b9060005260206000200154905092915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b600080600061515685856151b2565b915091506118e7816151f7565b60008181526001830160205260408120546151aa575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556109b0565b5060006109b0565b60008082516041036151e85760208301516040840151606085015160001a6151dc8782858561535c565b945094505050506151f0565b506000905060025b9250929050565b600081600481111561520b5761520b615e6d565b036152135750565b600181600481111561522757615227615e6d565b036152745760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610cd8565b600281600481111561528857615288615e6d565b036152d55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610cd8565b60038160048111156152e9576152e9615e6d565b03610bca5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610cd8565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156153935750600090506003615442565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156153e7573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661543b57600060019250925050615442565b9150600090505b94509492505050565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610bca57600080fd5b60006020828403121561548b57600080fd5b81356148798161544b565b73ffffffffffffffffffffffffffffffffffffffff81168114610bca57600080fd5b80356154c381615496565b919050565b6000602082840312156154da57600080fd5b813561487981615496565b60008083601f8401126154f757600080fd5b50813567ffffffffffffffff81111561550f57600080fd5b6020830191508360208285010111156151f057600080fd5b60008060008060006080868803121561553f57600080fd5b853561554a81615496565b9450602086013561555a81615496565b935060408601359250606086013567ffffffffffffffff81111561557d57600080fd5b615589888289016154e5565b969995985093965092949392505050565b60008083601f8401126155ac57600080fd5b50813567ffffffffffffffff8111156155c457600080fd5b6020830191508360208260051b85010111156151f057600080fd5b803561ffff811681146154c357600080fd5b803563ffffffff811681146154c357600080fd5b60008060008060008060a0878903121561561e57600080fd5b863567ffffffffffffffff81111561563557600080fd5b61564189828a0161559a565b90975095506156549050602088016155df565b9350615662604088016155df565b9250615670606088016155df565b915061567e608088016155f1565b90509295509295509295565b60008060006040848603121561569f57600080fd5b833567ffffffffffffffff8111156156b657600080fd5b6156c28682870161559a565b90945092505060208401356156d681615496565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b81811015615719578351835292840192918401916001016156fd565b50909695505050505050565b6000806000806000806000806000806000806101208d8f03121561574857600080fd5b67ffffffffffffffff8d35111561575e57600080fd5b61576b8e8e358f0161559a565b909c509a5067ffffffffffffffff60208e0135111561578957600080fd5b6157998e60208f01358f0161559a565b909a5098506157aa60408e016154b8565b97506157b860608e016155df565b96506157c660808e016155df565b95506157d460a08e016155df565b94506157e260c08e016155f1565b93506157f060e08e016155f1565b925067ffffffffffffffff6101008e0135111561580c57600080fd5b61581d8e6101008f01358f016154e5565b81935080925050509295989b509295989b509295989b565b6000806040838503121561584857600080fd5b82356158538161544b565b9150602083013561586381615496565b809150509250929050565b6000806040838503121561588157600080fd5b82359150615891602084016155f1565b90509250929050565b600080600080604085870312156158b057600080fd5b843567ffffffffffffffff808211156158c857600080fd5b6158d48883890161559a565b909650945060208701359150808211156158ed57600080fd5b506158fa8782880161559a565b95989497509550505050565b6000806000806000806080878903121561591f57600080fd5b86359550602087013567ffffffffffffffff8082111561593e57600080fd5b61594a8a838b016154e5565b909750955060408901359450606089013591508082111561596a57600080fd5b5061597789828a016154e5565b979a9699509497509295939492505050565b60008060006060848603121561599e57600080fd5b6159a7846155f1565b92506159b5602085016155f1565b915060408401356bffffffffffffffffffffffff811681146156d657600080fd5b6000602082840312156159e857600080fd5b5035919050565b600080600080600080600060c0888a031215615a0a57600080fd5b873567ffffffffffffffff811115615a2157600080fd5b615a2d8a828b0161559a565b9098509650506020880135615a4181615496565b9450615a4f604089016155df565b9350615a5d606089016155df565b9250615a6b608089016155df565b9150615a7960a089016155f1565b905092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156109b0576109b0615a87565b80820281158282048414176109b0576109b0615a87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215615b2157600080fd5b815161487981615496565b600060208284031215615b3e57600080fd5b8151801515811461487957600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b7f57615b7f615a87565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115615be757600080fd5b8260051b80836020870137939093016020019392505050565b60a081526000615c1460a08301898b615bb5565b8281036020840152615c2781888a615bb5565b73ffffffffffffffffffffffffffffffffffffffff968716604085015263ffffffff95909516606084015250509216608090920191909152949350505050565b63ffffffff8281168282160390808211156150e3576150e3615a87565b600082615cba577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6bffffffffffffffffffffffff8281168282160390808211156150e3576150e3615a87565b6bffffffffffffffffffffffff818116838216028082169190828114615d0c57615d0c615a87565b505092915050565b6bffffffffffffffffffffffff8181168382160190808211156150e3576150e3615a87565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b868152608060208201526000615d9c608083018789615d39565b8560408401528281036060840152615db5818587615d39565b9998505050505050505050565b63ffffffff8181168382160190808211156150e3576150e3615a87565b6000825160005b81811015615e005760208186018101518583015201615de6565b506000920191825250919050565b600060208284031215615e2057600080fd5b81516148798161544b565b818103818111156109b0576109b0615a87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea26469706673582212202086abfba87dcf6ea36b2547ac97a3484a03eb7b5407802bfd6e431f878890dc64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ccccb68e1a848cbdb5b60a974e07aae143ed40c30000000000000000000000008d9710f0e193d3f95c0723eaaf1a81030dc9116d
-----Decoded View---------------
Arg [0] : _rewardTokenAddress (address): 0xcccCb68e1A848CBDB5b60a974E07aAE143ed40C3
Arg [1] : _worlds (address): 0x8D9710f0e193d3f95c0723eAAF1A81030Dc9116D
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000ccccb68e1a848cbdb5b60a974e07aae143ed40c3
Arg [1] : 0000000000000000000000008d9710f0e193d3f95c0723eaaf1a81030dc9116d
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.