Source Code
Latest 25 from a total of 86 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Stake | 23277478 | 182 days ago | IN | 0 ETH | 0.00008484 | ||||
| Stake | 23217400 | 191 days ago | IN | 0 ETH | 0.00002938 | ||||
| Stake | 23208512 | 192 days ago | IN | 0 ETH | 0.00003913 | ||||
| Stake | 23202879 | 193 days ago | IN | 0 ETH | 0.00004081 | ||||
| Stake | 23198673 | 193 days ago | IN | 0 ETH | 0.00041184 | ||||
| Stake | 23186692 | 195 days ago | IN | 0 ETH | 0.00086351 | ||||
| Stake | 23183945 | 195 days ago | IN | 0 ETH | 0.00019393 | ||||
| Stake | 23180127 | 196 days ago | IN | 0 ETH | 0.00002547 | ||||
| Stake | 23177395 | 196 days ago | IN | 0 ETH | 0.00066055 | ||||
| Stake | 23176513 | 196 days ago | IN | 0 ETH | 0.00079745 | ||||
| Stake | 23175696 | 196 days ago | IN | 0 ETH | 0.00018465 | ||||
| Stake | 23175279 | 197 days ago | IN | 0 ETH | 0.00068518 | ||||
| Stake | 23174478 | 197 days ago | IN | 0 ETH | 0.00008501 | ||||
| Stake | 23174459 | 197 days ago | IN | 0 ETH | 0.00007883 | ||||
| Stake | 23171028 | 197 days ago | IN | 0 ETH | 0.00017965 | ||||
| Stake | 23168841 | 197 days ago | IN | 0 ETH | 0.00015361 | ||||
| Stake | 23163288 | 198 days ago | IN | 0 ETH | 0.0005909 | ||||
| Stake | 23160084 | 199 days ago | IN | 0 ETH | 0.00055674 | ||||
| Stake | 23159900 | 199 days ago | IN | 0 ETH | 0.00004165 | ||||
| Stake | 23154858 | 199 days ago | IN | 0 ETH | 0.00016747 | ||||
| Stake | 23153679 | 200 days ago | IN | 0 ETH | 0.00003081 | ||||
| Stake | 23152721 | 200 days ago | IN | 0 ETH | 0.0001373 | ||||
| Stake | 23150276 | 200 days ago | IN | 0 ETH | 0.00005138 | ||||
| Stake | 23148155 | 200 days ago | IN | 0 ETH | 0.0001005 | ||||
| Stake | 23146762 | 200 days ago | IN | 0 ETH | 0.00055145 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
|||
|---|---|---|---|---|---|---|---|---|
| On ERC721Receive... | 23277478 | 182 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23277478 | 182 days ago | 0 ETH | |||||
| On ERC721Receive... | 23277478 | 182 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23277478 | 182 days ago | 0 ETH | |||||
| On ERC721Receive... | 23217400 | 191 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23217400 | 191 days ago | 0 ETH | |||||
| On ERC721Receive... | 23208512 | 192 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23208512 | 192 days ago | 0 ETH | |||||
| On ERC721Receive... | 23208512 | 192 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23208512 | 192 days ago | 0 ETH | |||||
| On ERC721Receive... | 23202879 | 193 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23202879 | 193 days ago | 0 ETH | |||||
| On ERC721Receive... | 23198673 | 193 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23198673 | 193 days ago | 0 ETH | |||||
| On ERC721Receive... | 23198673 | 193 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23198673 | 193 days ago | 0 ETH | |||||
| On ERC721Receive... | 23186692 | 195 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23186692 | 195 days ago | 0 ETH | |||||
| On ERC721Receive... | 23186692 | 195 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23186692 | 195 days ago | 0 ETH | |||||
| On ERC721Receive... | 23186692 | 195 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23186692 | 195 days ago | 0 ETH | |||||
| On ERC721Receive... | 23183945 | 195 days ago | 0 ETH | |||||
| Safe Transfer Fr... | 23183945 | 195 days ago | 0 ETH | |||||
| On ERC721Receive... | 23183945 | 195 days ago | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ERC721VaultLockable
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/**
* @title ERC721VaultLockable
* @author RebaseRicky
* @notice A pre-mainnet launch staking vault for Tapout Genesis NFTs that receives and distributes ETH rewards.
* @dev Users can stake NFTs to earn ETH rewards, which are claimable at any time.
* However, NFT withdrawals are disabled by default and can only be enabled by an admin,
* incentivizing users to keep their NFTs locked in the vault.
*/
contract ERC721VaultLockable is IERC721Receiver, ReentrancyGuard, AccessControl {
using FixedPointMathLib for uint256;
// --- Roles ---
bytes32 public constant DELEGATE_ROLE = keccak256("DELEGATE_ROLE");
// --- State Variables ---
IERC721 public nft;
address public treasury;
uint256 public totalSupply;
uint256 private constant _MULTIPLIER = 1e18;
uint256 public rewardIndex;
// The single control flag for the pre-launch lock-in period.
bool public withdrawalsEnabled;
// Mappings
mapping(address => uint256) public balanceOf;
mapping(address => uint256) private rewardIndexOf;
mapping(address => uint256) private earned;
mapping(address => uint256) public claimedRewards;
mapping(address => uint256[]) private stakedTokenIds;
mapping(uint256 => address) private stakedTokenOwner;
mapping(address => mapping(uint256 => uint256)) private tokenIdToIndex;
// --- Events ---
event Staked(address indexed user, uint256 indexed tokenId);
event Unstaked(address indexed user, uint256 indexed tokenId);
event Claimed(address indexed user, uint256 amount, uint256 totalClaimed);
event Received(uint256 amount, uint256 rewardIndex);
event RewardsUpdated(address indexed user, uint256 newEarned, uint256 newIndex);
event WithdrawalsEnabledSet(bool enabled);
event TreasuryUpdated(address indexed newTreasury);
event NFTContractSet(address indexed nftContract);
// --- Errors ---
error NotNFTOwner();
error NFTNotEligibleForStaking();
error NFTNotStaked();
error NFTNotStakedByUser();
error ZeroRewards();
error TransferFailed();
error UnauthorizedTransfer();
error ZeroAddress();
error EmptyTokenArray();
error WithdrawalsNotEnabled();
error AlreadyInitialized();
error NotInitialized();
// --- Structs ---
struct UserInfo {
uint256 pendingRewards;
uint256 claimedRewards;
uint256[] stakedTokenIds;
}
// --- Constructor ---
/// @notice Sets up the vault, initial roles, and treasury. The NFT contract must be set later via initialize().
/// @param _deployer The address that will be granted the DEFAULT_ADMIN_ROLE and DELEGATE_ROLE.
/// @param _initialAdmin The address that will be granted the initial DELEGATE role.
/// @param _treasury The address to receive funds sent to this contract before any NFTs are staked.
constructor(address _deployer, address _initialAdmin, address _treasury) {
if (_deployer == address(0) || _initialAdmin == address(0) || _treasury == address(0)) {
revert ZeroAddress();
}
treasury = _treasury;
emit TreasuryUpdated(_treasury); // <-- ADDED: Emit event for initial treasury
_grantRole(DEFAULT_ADMIN_ROLE, _deployer);
_grantRole(DELEGATE_ROLE, _deployer);
_grantRole(DELEGATE_ROLE, _initialAdmin);
// Withdrawals are disabled by default for the pre-launch phase.
withdrawalsEnabled = false;
emit WithdrawalsEnabledSet(false); // <-- ADDED: Emit event for initial withdrawal state
}
// --- Modifiers ---
modifier isInitialized() {
if (address(nft) == address(0)) revert NotInitialized();
_;
}
/// @notice Sets the NFT contract address.
/// @dev This function is critical for the contract's operation and can ONLY be called once by the admin.
/// It must be called before any staking or unstaking can occur.
/// @param _nft The address of the ERC721 contract to be staked.
function initialize(address _nft) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (address(nft) != address(0)) revert AlreadyInitialized();
if (_nft == address(0)) revert ZeroAddress();
nft = IERC721(_nft);
emit NFTContractSet(_nft);
}
// --- Reward Distribution ---
/// @notice Receives ETH. If NFTs are staked, it distributes rewards. If not, it forwards ETH to the treasury.
receive() external payable {
if (totalSupply > 0) {
uint256 reward = msg.value.mulDiv(_MULTIPLIER, totalSupply);
rewardIndex += reward;
emit Received(msg.value, rewardIndex);
} else {
(bool success, ) = payable(treasury).call{value: msg.value}("");
if (!success) revert TransferFailed();
}
}
// --- User-Facing Functions ---
/// @notice Allows users to stake their NFTs.
/// @param tokenIds Array of token IDs to stake.
function stake(uint256[] calldata tokenIds) external nonReentrant isInitialized {
uint256 length = tokenIds.length;
if (length == 0) revert EmptyTokenArray();
_updateRewards(msg.sender);
balanceOf[msg.sender] += length;
totalSupply += length;
address sender = msg.sender;
uint256[] storage userTokens = stakedTokenIds[sender];
for (uint256 i = 0; i < length; i++) {
uint256 tokenId = tokenIds[i];
nft.safeTransferFrom(sender, address(this), tokenId);
stakedTokenOwner[tokenId] = sender;
tokenIdToIndex[sender][tokenId] = userTokens.length;
userTokens.push(tokenId);
emit Staked(sender, tokenId);
}
}
/// @notice Allows users to unstake their NFTs, ONLY if withdrawals are enabled by an admin.
/// @param tokenIds Array of token IDs to unstake.
function unstake(uint256[] calldata tokenIds) external nonReentrant isInitialized {
if (!withdrawalsEnabled) revert WithdrawalsNotEnabled();
uint256 length = tokenIds.length;
if (length == 0) revert EmptyTokenArray();
address sender = msg.sender;
_updateRewards(sender);
balanceOf[sender] -= length;
totalSupply -= length;
for (uint256 i = 0; i < length; i++) {
uint256 tokenId = tokenIds[i];
if (stakedTokenOwner[tokenId] != sender) revert NFTNotStakedByUser();
nft.safeTransferFrom(address(this), sender, tokenId);
delete stakedTokenOwner[tokenId];
_removeStakedTokenId(sender, tokenId);
emit Unstaked(sender, tokenId);
}
}
/// @notice Allows users to claim their staking rewards at any time.
/// @return The amount of rewards claimed.
function claim() external nonReentrant returns (uint256) {
address sender = msg.sender;
_updateRewards(sender);
uint256 claimAmount = earned[sender];
if (claimAmount == 0) revert ZeroRewards();
earned[sender] = 0;
(bool success, ) = payable(sender).call{value: claimAmount}("");
if (!success) {
// If the transfer fails, the entire transaction reverts,
// automatically restoring earned[sender] to its original value.
// The manual reversal logic is not needed.
revert TransferFailed();
}
claimedRewards[sender] += claimAmount;
emit Claimed(sender, claimAmount, claimedRewards[sender]);
return claimAmount;
}
// --- Admin Functions ---
/// @notice Enables or disables NFT withdrawals. Only callable by an admin.
function setWithdrawalsEnabled(bool _enabled) external onlyRole(DELEGATE_ROLE) {
withdrawalsEnabled = _enabled;
emit WithdrawalsEnabledSet(_enabled);
}
/// @notice Updates the treasury address. Only callable by an admin.
function setTreasury(address _newTreasury) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_newTreasury == address(0)) revert ZeroAddress();
treasury = _newTreasury;
emit TreasuryUpdated(_newTreasury);
}
// --- View Functions ---
function getUserInfo(address user) public view returns (UserInfo memory) {
if (user == address(0)) revert ZeroAddress();
return UserInfo({
pendingRewards: getPendingRewards(user),
claimedRewards: claimedRewards[user],
stakedTokenIds: stakedTokenIds[user]
});
}
function getPendingRewards(address account) public view returns (uint256) {
return earned[account] + _calculateRewards(account);
}
function isTokenStakedByUser(uint256 tokenId, address user) external view returns (bool) {
return stakedTokenOwner[tokenId] == user;
}
// --- Internal & Private Functions ---
function _calculateRewards(address account) private view returns (uint256) {
uint256 nftCount = balanceOf[account];
if (nftCount == 0 || rewardIndex <= rewardIndexOf[account]) return 0;
uint256 indexDiff = rewardIndex - rewardIndexOf[account];
return nftCount.mulDiv(indexDiff, _MULTIPLIER);
}
function _updateRewards(address account) private {
uint256 newEarned = _calculateRewards(account);
if (newEarned > 0) {
earned[account] += newEarned;
emit RewardsUpdated(account, earned[account], rewardIndex);
}
rewardIndexOf[account] = rewardIndex;
}
function _removeStakedTokenId(address user, uint256 tokenId) private {
uint256[] storage userTokens = stakedTokenIds[user];
uint256 index = tokenIdToIndex[user][tokenId];
uint256 lastTokenId = userTokens[userTokens.length - 1];
userTokens[index] = lastTokenId;
tokenIdToIndex[user][lastTokenId] = index;
delete tokenIdToIndex[user][tokenId];
userTokens.pop();
}
// --- ERC721 Receiver ---
function onERC721Received(address operator, address, uint256, bytes calldata) external isInitialized returns (bytes4) {
if (msg.sender != address(nft)) revert NFTNotEligibleForStaking();
if (operator != address(this)) revert UnauthorizedTransfer();
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC-721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @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 EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* 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;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
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
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// 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 v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if gt(x, div(not(0), y)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if iszero(eq(div(z, y), x)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := add(iszero(iszero(mod(z, WAD))), div(z, WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(mul(y, eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
/// Note: This function is an approximation.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
/// Note: This function is an approximation. Monotonically increasing.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
(int256 wad, int256 p) = (int256(WAD), x);
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (uint256(w >> 63) == uint256(0)) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == uint256(0)) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != uint256(0));
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c == uint256(0)) return w;
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `a * b == x * y`, with full precision.
function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0))))
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`.
for {} 1 {} {
// If overflows.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
let r := mulmod(x, y, d) // Compute remainder using mulmod.
let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.
// Make sure `z` is less than `2**256`. Also prevents `d == 0`.
// Placing the check here seems to give more optimal stack operations.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
d := div(d, t) // Divide `d` by `t`, which is a power of two.
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use 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.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
z :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256
)
break
}
z := div(z, d)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.
/// Performs the full 512 bit calculation regardless.
function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z)))
let t := and(d, sub(0, d))
let r := mulmod(x, y, d)
d := div(d, t)
let inv := xor(2, mul(3, d))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
z :=
mul(
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv)
)
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
z = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
z := add(z, 1)
if iszero(z) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Calculates `floor(x * y / 2 ** n)` with full precision.
/// Throws if result overflows a uint256.
/// Credit to Philogy under MIT license:
/// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol
function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`.
for {} 1 {} {
if iszero(or(iszero(x), eq(div(z, x), y))) {
let k := and(n, 0xff) // `n`, cleaned.
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
// | p1 | z |
// Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 |
// Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 |
// Check that final `z` doesn't overflow by checking that p1_0 = 0.
if iszero(shr(k, p1)) {
z := add(shl(sub(256, k), p1), shr(k, z))
break
}
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
z := shr(and(n, 0xff), z)
break
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(z, d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(z, d))), div(z, d))
}
}
/// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`.
function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) {
/// @solidity memory-safe-assembly
assembly {
let g := n
let r := mod(a, n)
for { let y := 1 } 1 {} {
let q := div(g, r)
let t := g
g := r
r := sub(t, mul(r, q))
let u := x
x := y
y := sub(u, mul(y, q))
if iszero(r) { break }
}
x := mul(eq(g, 1), add(x, mul(slt(x, 0), n)))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`. Alias for `saturatingSub`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `max(0, x - y)`.
function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `min(2 ** 256 - 1, x + y)`.
function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(sub(0, lt(add(x, y), x)), add(x, y))
}
}
/// @dev Returns `min(2 ** 256 - 1, x * y)`.
function saturatingMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(sub(or(iszero(x), eq(div(mul(x, y), x), y)), 1), mul(x, y))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, address x, address y) internal pure returns (address z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `x != 0 ? x : y`, without branching.
function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(x)))
}
}
/// @dev Returns `x != bytes32(0) ? x : y`, without branching.
function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(x)))
}
}
/// @dev Returns `x != address(0) ? x : y`, without branching.
function coalesce(address x, address y) internal pure returns (address z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(shl(96, x))))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if x {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`, rounded down.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`, rounded down.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/snekmate/utils/math.vy
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// Makeshift lookup table to nudge the approximate log2 result.
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
// Newton-Raphson's.
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
// Round down.
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);
z = (1 + sqrt(x)) * 10 ** 9;
z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;
}
/// @solidity memory-safe-assembly
assembly {
z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down.
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);
z = (1 + cbrt(x)) * 10 ** 12;
z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;
}
/// @solidity memory-safe-assembly
assembly {
let p := x
for {} 1 {} {
if iszero(shr(229, p)) {
if iszero(shr(199, p)) {
p := mul(p, 100000000000000000) // 10 ** 17.
break
}
p := mul(p, 100000000) // 10 ** 8.
break
}
if iszero(shr(249, p)) { p := mul(p, 100) }
break
}
let t := mulmod(mul(z, z), z, p)
z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down.
}
}
/// @dev Returns `sqrt(x * y)`. Also called the geometric mean.
function mulSqrt(uint256 x, uint256 y) internal pure returns (uint256 z) {
if (x == y) return x;
uint256 p = rawMul(x, y);
if (y == rawDiv(p, x)) return sqrt(p);
for (z = saturatingMul(rawAdd(sqrt(x), 1), rawAdd(sqrt(y), 1));; z = avg(z, p)) {
if ((p = fullMulDivUnchecked(x, y, z)) >= z) break;
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := 1
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for {} x { x := sub(x, 1) } { z := mul(z, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards zero.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
unchecked {
z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255);
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)
internal
pure
returns (uint256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
unchecked {
if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);
return a - fullMulDiv(a - b, t - begin, end - begin);
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)
internal
pure
returns (int256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
// forgefmt: disable-next-item
unchecked {
if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a),
uint256(t - begin), uint256(end - begin)));
return int256(uint256(a) - fullMulDiv(uint256(a - b),
uint256(t - begin), uint256(end - begin)));
}
}
/// @dev Returns if `x` is an even number. Some people may need this.
function isEven(uint256 x) internal pure returns (bool) {
return x & uint256(1) == uint256(0);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_deployer","type":"address"},{"internalType":"address","name":"_initialAdmin","type":"address"},{"internalType":"address","name":"_treasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"EmptyTokenArray","type":"error"},{"inputs":[],"name":"NFTNotEligibleForStaking","type":"error"},{"inputs":[],"name":"NFTNotStaked","type":"error"},{"inputs":[],"name":"NFTNotStakedByUser","type":"error"},{"inputs":[],"name":"NotInitialized","type":"error"},{"inputs":[],"name":"NotNFTOwner","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UnauthorizedTransfer","type":"error"},{"inputs":[],"name":"WithdrawalsNotEnabled","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroRewards","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalClaimed","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"}],"name":"NFTContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardIndex","type":"uint256"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"newEarned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newIndex","type":"uint256"}],"name":"RewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"WithdrawalsEnabledSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserInfo","outputs":[{"components":[{"internalType":"uint256","name":"pendingRewards","type":"uint256"},{"internalType":"uint256","name":"claimedRewards","type":"uint256"},{"internalType":"uint256[]","name":"stakedTokenIds","type":"uint256[]"}],"internalType":"struct ERC721VaultLockable.UserInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nft","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"isTokenStakedByUser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nft","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setWithdrawalsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"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":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
608060405234801561001057600080fd5b5060405161187d38038061187d83398101604081905261002f916101fd565b60016000556001600160a01b038316158061005157506001600160a01b038216155b8061006357506001600160a01b038116155b156100815760405163d92e233d60e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d190600090a26100d360008461014c565b506100ec60008051602061185d8339815191528461014c565b5061010560008051602061185d8339815191528361014c565b506006805460ff19169055604051600081527fd889a4b5aef69cd23eeb1c54b8a1bff3bcea1ec9ad73240c10c3bad638c2a2d69060200160405180910390a1505050610240565b60008281526001602090815260408083206001600160a01b038516845290915281205460ff166101d75760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45060016101db565b5060005b92915050565b80516001600160a01b03811681146101f857600080fd5b919050565b60008060006060848603121561021257600080fd5b61021b846101e1565b9250610229602085016101e1565b9150610237604085016101e1565b90509250925092565b61160e8061024f6000396000f3fe60806040526004361061016a5760003560e01c80636386c1c7116100d1578063c4d66de81161008a578063e449f34111610064578063e449f341146105a3578063e9ee2fa9146105c3578063f0f44260146105d9578063f6ed2017146105f957600080fd5b8063c4d66de814610549578063d0dbcd2414610569578063d547741f1461058357600080fd5b80636386c1c71461045957806370a082311461048657806391d14854146104b3578063a217fddf146104d3578063bd834345146104e8578063c0ba241b1461051557600080fd5b80632f2ff15d116101235780632f2ff15d1461037057806336568abe1461039057806347ccca02146103b05780634e71d92d146103e85780635aca7d9b146103fd57806361d027b31461043957600080fd5b806301ffc9a71461026d5780630a179327146102a25780630fbf0a93146102c2578063150b7a02146102e257806318160ddd1461031b578063248a9ca31461033f57600080fd5b3661026857600454156101f0576000610198670de0b6b3a7640000600454346106199092919063ffffffff16565b905080600560008282546101ac9190611339565b90915550506005546040805134815260208101929092527f49b838b1f120c3d2fb431047a22c4c3f41cbebfeec469a48c6d0f94db4b831b5910160405180910390a1005b6003546040516000916001600160a01b03169034908381818185875af1925050503d806000811461023d576040519150601f19603f3d011682016040523d82523d6000602084013e610242565b606091505b5050905080610264576040516312171d8360e31b815260040160405180910390fd5b505b005b600080fd5b34801561027957600080fd5b5061028d61028836600461134c565b61063f565b60405190151581526020015b60405180910390f35b3480156102ae57600080fd5b506102666102bd36600461137d565b610676565b3480156102ce57600080fd5b506102666102dd36600461139f565b6106e8565b3480156102ee57600080fd5b506103026102fd366004611432565b6108c0565b6040516001600160e01b03199091168152602001610299565b34801561032757600080fd5b5061033160045481565b604051908152602001610299565b34801561034b57600080fd5b5061033161035a3660046114cf565b6000908152600160208190526040909120015490565b34801561037c57600080fd5b5061026661038b3660046114e8565b610952565b34801561039c57600080fd5b506102666103ab3660046114e8565b61097e565b3480156103bc57600080fd5b506002546103d0906001600160a01b031681565b6040516001600160a01b039091168152602001610299565b3480156103f457600080fd5b506103316109b6565b34801561040957600080fd5b5061028d6104183660046114e8565b6000918252600c6020526040909120546001600160a01b0390811691161490565b34801561044557600080fd5b506003546103d0906001600160a01b031681565b34801561046557600080fd5b50610479610474366004611514565b610b14565b604051610299919061152f565b34801561049257600080fd5b506103316104a1366004611514565b60076020526000908152604090205481565b3480156104bf57600080fd5b5061028d6104ce3660046114e8565b610bf5565b3480156104df57600080fd5b50610331600081565b3480156104f457600080fd5b50610331610503366004611514565b600a6020526000908152604090205481565b34801561052157600080fd5b506103317f1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f1581565b34801561055557600080fd5b50610266610564366004611514565b610c20565b34801561057557600080fd5b5060065461028d9060ff1681565b34801561058f57600080fd5b5061026661059e3660046114e8565b610cc6565b3480156105af57600080fd5b506102666105be36600461139f565b610cec565b3480156105cf57600080fd5b5061033160055481565b3480156105e557600080fd5b506102666105f4366004611514565b610efa565b34801561060557600080fd5b50610331610614366004611514565b610f77565b828202831584820484141782026106385763ad251c276000526004601cfd5b0492915050565b60006001600160e01b03198216637965db0b60e01b148061067057506301ffc9a760e01b6001600160e01b03198316145b92915050565b7f1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f156106a081610fa5565b6006805460ff19168315159081179091556040519081527fd889a4b5aef69cd23eeb1c54b8a1bff3bcea1ec9ad73240c10c3bad638c2a2d69060200160405180910390a15050565b6106f0610fb2565b6002546001600160a01b0316610719576040516321c4e35760e21b815260040160405180910390fd5b80600081900361073c576040516337e4edd960e21b815260040160405180910390fd5b61074533610fdc565b3360009081526007602052604081208054839290610764908490611339565b92505081905550806004600082825461077d9190611339565b9091555050336000818152600b60205260408120905b838110156108ae5760008686838181106107af576107af611599565b600254604051632142170760e11b81526001600160a01b038981166004830152306024830152602093909302949094013560448501819052945016916342842e0e9150606401600060405180830381600087803b15801561080f57600080fd5b505af1158015610823573d6000803e3d6000fd5b5050506000828152600c6020908152604080832080546001600160a01b0319166001600160a01b038a169081179091558754818552600d845282852087865284528285208190556001810189558885529284209092018590555184935090917f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d91a350600101610793565b505050506108bc6001600055565b5050565b6002546000906001600160a01b03166108ec576040516321c4e35760e21b815260040160405180910390fd5b6002546001600160a01b0316331461091757604051638d4ab38960e01b815260040160405180910390fd5b6001600160a01b0386163014610940576040516325cdf54f60e21b815260040160405180910390fd5b50630a85bd0160e11b95945050505050565b6000828152600160208190526040909120015461096e81610fa5565b6109788383611098565b50505050565b6001600160a01b03811633146109a75760405163334bd91960e11b815260040160405180910390fd5b6109b18282611111565b505050565b60006109c0610fb2565b336109ca81610fdc565b6001600160a01b03811660009081526009602052604081205490819003610a045760405163899aaa9d60e01b815260040160405180910390fd5b6001600160a01b0382166000818152600960205260408082208290555190919083908381818185875af1925050503d8060008114610a5e576040519150601f19603f3d011682016040523d82523d6000602084013e610a63565b606091505b5050905080610a85576040516312171d8360e31b815260040160405180910390fd5b6001600160a01b0383166000908152600a602052604081208054849290610aad908490611339565b90915550506001600160a01b0383166000818152600a6020908152604091829020548251868152918201527f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a910160405180910390a250915050610b116001600055565b90565b610b3860405180606001604052806000815260200160008152602001606081525090565b6001600160a01b038216610b5f5760405163d92e233d60e01b815260040160405180910390fd5b6040518060600160405280610b7384610f77565b81526001600160a01b0384166000818152600a602090815260408083205482860152928252600b8152908290208054835181840281018401855281815293909401939091830182828015610be657602002820191906000526020600020905b815481526020019060010190808311610bd2575b50505050508152509050919050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000610c2b81610fa5565b6002546001600160a01b031615610c545760405162dc149f60e41b815260040160405180910390fd5b6001600160a01b038216610c7b5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0384169081179091556040517f5a6a54be6929433a25d1b5103e7dea8d9440b7903216e380344a320ca1cdd85f90600090a25050565b60008281526001602081905260409091200154610ce281610fa5565b6109788383611111565b610cf4610fb2565b6002546001600160a01b0316610d1d576040516321c4e35760e21b815260040160405180910390fd5b60065460ff16610d40576040516309a2a07d60e11b815260040160405180910390fd5b806000819003610d63576040516337e4edd960e21b815260040160405180910390fd5b33610d6d81610fdc565b6001600160a01b03811660009081526007602052604081208054849290610d959084906115af565b925050819055508160046000828254610dae91906115af565b90915550600090505b82811015610eed576000858583818110610dd357610dd3611599565b602090810292909201356000818152600c909352604090922054919250506001600160a01b03848116911614610e1c5760405163ec76d92760e01b815260040160405180910390fd5b600254604051632142170760e11b81523060048201526001600160a01b03858116602483015260448201849052909116906342842e0e90606401600060405180830381600087803b158015610e7057600080fd5b505af1158015610e84573d6000803e3d6000fd5b5050506000828152600c6020526040902080546001600160a01b031916905550610eae838261117e565b60405181906001600160a01b038516907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f7590600090a350600101610db7565b5050506108bc6001600055565b6000610f0581610fa5565b6001600160a01b038216610f2c5760405163d92e233d60e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0384169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d190600090a25050565b6000610f8282611255565b6001600160a01b0383166000908152600960205260409020546106709190611339565b610faf81336112e6565b50565b600260005403610fd557604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b6000610fe782611255565b90508015611078576001600160a01b03821660009081526009602052604081208054839290611017908490611339565b90915550506001600160a01b038216600081815260096020526040908190205460055491517fca40132af767b10947fd7de6fe4074613c5850cc28b8d0aa94adb189bfb716be9261106f928252602082015260400190565b60405180910390a25b506005546001600160a01b03909116600090815260086020526040902055565b60006110a48383610bf5565b6111095760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a4506001610670565b506000610670565b600061111d8383610bf5565b156111095760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610670565b6001600160a01b0382166000908152600b60209081526040808320600d835281842085855290925282205481549192909183906111bd906001906115af565b815481106111cd576111cd611599565b90600052602060002001549050808383815481106111ed576111ed611599565b6000918252602080832091909101929092556001600160a01b0387168152600d82526040808220848352909252818120849055858152908120558254839080611238576112386115c2565b600190038181906000526020600020016000905590555050505050565b6001600160a01b03811660009081526007602052604081205480158061129557506001600160a01b03831660009081526008602052604090205460055411155b156112a35750600092915050565b6001600160a01b0383166000908152600860205260408120546005546112c991906115af565b90506112de8282670de0b6b3a7640000610619565b949350505050565b6112f08282610bf5565b6108bc5760405163e2517d3f60e01b81526001600160a01b03821660048201526024810183905260440160405180910390fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561067057610670611323565b60006020828403121561135e57600080fd5b81356001600160e01b03198116811461137657600080fd5b9392505050565b60006020828403121561138f57600080fd5b8135801515811461137657600080fd5b600080602083850312156113b257600080fd5b823567ffffffffffffffff8111156113c957600080fd5b8301601f810185136113da57600080fd5b803567ffffffffffffffff8111156113f157600080fd5b8560208260051b840101111561140657600080fd5b6020919091019590945092505050565b80356001600160a01b038116811461142d57600080fd5b919050565b60008060008060006080868803121561144a57600080fd5b61145386611416565b945061146160208701611416565b935060408601359250606086013567ffffffffffffffff81111561148457600080fd5b8601601f8101881361149557600080fd5b803567ffffffffffffffff8111156114ac57600080fd5b8860208284010111156114be57600080fd5b959894975092955050506020019190565b6000602082840312156114e157600080fd5b5035919050565b600080604083850312156114fb57600080fd5b8235915061150b60208401611416565b90509250929050565b60006020828403121561152657600080fd5b61137682611416565b602081526000608082018351602084015260208401516040840152604084015160608085015281815180845260a086019150602083019350600092505b8083101561158f578351825260208201915060208401935060018301925061156c565b5095945050505050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561067057610670611323565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220c1c13db05cbedfeb6655c613f26160f5202e6d488eebe36d9670c019b35e936f64736f6c634300081a00331a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f150000000000000000000000008ff243a318f02cad7efe5c2d950bd6d6388a2bf2000000000000000000000000ec3475f942ae76014997419fc69c20ce052b889f0000000000000000000000008ff243a318f02cad7efe5c2d950bd6d6388a2bf2
Deployed Bytecode
0x60806040526004361061016a5760003560e01c80636386c1c7116100d1578063c4d66de81161008a578063e449f34111610064578063e449f341146105a3578063e9ee2fa9146105c3578063f0f44260146105d9578063f6ed2017146105f957600080fd5b8063c4d66de814610549578063d0dbcd2414610569578063d547741f1461058357600080fd5b80636386c1c71461045957806370a082311461048657806391d14854146104b3578063a217fddf146104d3578063bd834345146104e8578063c0ba241b1461051557600080fd5b80632f2ff15d116101235780632f2ff15d1461037057806336568abe1461039057806347ccca02146103b05780634e71d92d146103e85780635aca7d9b146103fd57806361d027b31461043957600080fd5b806301ffc9a71461026d5780630a179327146102a25780630fbf0a93146102c2578063150b7a02146102e257806318160ddd1461031b578063248a9ca31461033f57600080fd5b3661026857600454156101f0576000610198670de0b6b3a7640000600454346106199092919063ffffffff16565b905080600560008282546101ac9190611339565b90915550506005546040805134815260208101929092527f49b838b1f120c3d2fb431047a22c4c3f41cbebfeec469a48c6d0f94db4b831b5910160405180910390a1005b6003546040516000916001600160a01b03169034908381818185875af1925050503d806000811461023d576040519150601f19603f3d011682016040523d82523d6000602084013e610242565b606091505b5050905080610264576040516312171d8360e31b815260040160405180910390fd5b505b005b600080fd5b34801561027957600080fd5b5061028d61028836600461134c565b61063f565b60405190151581526020015b60405180910390f35b3480156102ae57600080fd5b506102666102bd36600461137d565b610676565b3480156102ce57600080fd5b506102666102dd36600461139f565b6106e8565b3480156102ee57600080fd5b506103026102fd366004611432565b6108c0565b6040516001600160e01b03199091168152602001610299565b34801561032757600080fd5b5061033160045481565b604051908152602001610299565b34801561034b57600080fd5b5061033161035a3660046114cf565b6000908152600160208190526040909120015490565b34801561037c57600080fd5b5061026661038b3660046114e8565b610952565b34801561039c57600080fd5b506102666103ab3660046114e8565b61097e565b3480156103bc57600080fd5b506002546103d0906001600160a01b031681565b6040516001600160a01b039091168152602001610299565b3480156103f457600080fd5b506103316109b6565b34801561040957600080fd5b5061028d6104183660046114e8565b6000918252600c6020526040909120546001600160a01b0390811691161490565b34801561044557600080fd5b506003546103d0906001600160a01b031681565b34801561046557600080fd5b50610479610474366004611514565b610b14565b604051610299919061152f565b34801561049257600080fd5b506103316104a1366004611514565b60076020526000908152604090205481565b3480156104bf57600080fd5b5061028d6104ce3660046114e8565b610bf5565b3480156104df57600080fd5b50610331600081565b3480156104f457600080fd5b50610331610503366004611514565b600a6020526000908152604090205481565b34801561052157600080fd5b506103317f1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f1581565b34801561055557600080fd5b50610266610564366004611514565b610c20565b34801561057557600080fd5b5060065461028d9060ff1681565b34801561058f57600080fd5b5061026661059e3660046114e8565b610cc6565b3480156105af57600080fd5b506102666105be36600461139f565b610cec565b3480156105cf57600080fd5b5061033160055481565b3480156105e557600080fd5b506102666105f4366004611514565b610efa565b34801561060557600080fd5b50610331610614366004611514565b610f77565b828202831584820484141782026106385763ad251c276000526004601cfd5b0492915050565b60006001600160e01b03198216637965db0b60e01b148061067057506301ffc9a760e01b6001600160e01b03198316145b92915050565b7f1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f156106a081610fa5565b6006805460ff19168315159081179091556040519081527fd889a4b5aef69cd23eeb1c54b8a1bff3bcea1ec9ad73240c10c3bad638c2a2d69060200160405180910390a15050565b6106f0610fb2565b6002546001600160a01b0316610719576040516321c4e35760e21b815260040160405180910390fd5b80600081900361073c576040516337e4edd960e21b815260040160405180910390fd5b61074533610fdc565b3360009081526007602052604081208054839290610764908490611339565b92505081905550806004600082825461077d9190611339565b9091555050336000818152600b60205260408120905b838110156108ae5760008686838181106107af576107af611599565b600254604051632142170760e11b81526001600160a01b038981166004830152306024830152602093909302949094013560448501819052945016916342842e0e9150606401600060405180830381600087803b15801561080f57600080fd5b505af1158015610823573d6000803e3d6000fd5b5050506000828152600c6020908152604080832080546001600160a01b0319166001600160a01b038a169081179091558754818552600d845282852087865284528285208190556001810189558885529284209092018590555184935090917f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d91a350600101610793565b505050506108bc6001600055565b5050565b6002546000906001600160a01b03166108ec576040516321c4e35760e21b815260040160405180910390fd5b6002546001600160a01b0316331461091757604051638d4ab38960e01b815260040160405180910390fd5b6001600160a01b0386163014610940576040516325cdf54f60e21b815260040160405180910390fd5b50630a85bd0160e11b95945050505050565b6000828152600160208190526040909120015461096e81610fa5565b6109788383611098565b50505050565b6001600160a01b03811633146109a75760405163334bd91960e11b815260040160405180910390fd5b6109b18282611111565b505050565b60006109c0610fb2565b336109ca81610fdc565b6001600160a01b03811660009081526009602052604081205490819003610a045760405163899aaa9d60e01b815260040160405180910390fd5b6001600160a01b0382166000818152600960205260408082208290555190919083908381818185875af1925050503d8060008114610a5e576040519150601f19603f3d011682016040523d82523d6000602084013e610a63565b606091505b5050905080610a85576040516312171d8360e31b815260040160405180910390fd5b6001600160a01b0383166000908152600a602052604081208054849290610aad908490611339565b90915550506001600160a01b0383166000818152600a6020908152604091829020548251868152918201527f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a910160405180910390a250915050610b116001600055565b90565b610b3860405180606001604052806000815260200160008152602001606081525090565b6001600160a01b038216610b5f5760405163d92e233d60e01b815260040160405180910390fd5b6040518060600160405280610b7384610f77565b81526001600160a01b0384166000818152600a602090815260408083205482860152928252600b8152908290208054835181840281018401855281815293909401939091830182828015610be657602002820191906000526020600020905b815481526020019060010190808311610bd2575b50505050508152509050919050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000610c2b81610fa5565b6002546001600160a01b031615610c545760405162dc149f60e41b815260040160405180910390fd5b6001600160a01b038216610c7b5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0384169081179091556040517f5a6a54be6929433a25d1b5103e7dea8d9440b7903216e380344a320ca1cdd85f90600090a25050565b60008281526001602081905260409091200154610ce281610fa5565b6109788383611111565b610cf4610fb2565b6002546001600160a01b0316610d1d576040516321c4e35760e21b815260040160405180910390fd5b60065460ff16610d40576040516309a2a07d60e11b815260040160405180910390fd5b806000819003610d63576040516337e4edd960e21b815260040160405180910390fd5b33610d6d81610fdc565b6001600160a01b03811660009081526007602052604081208054849290610d959084906115af565b925050819055508160046000828254610dae91906115af565b90915550600090505b82811015610eed576000858583818110610dd357610dd3611599565b602090810292909201356000818152600c909352604090922054919250506001600160a01b03848116911614610e1c5760405163ec76d92760e01b815260040160405180910390fd5b600254604051632142170760e11b81523060048201526001600160a01b03858116602483015260448201849052909116906342842e0e90606401600060405180830381600087803b158015610e7057600080fd5b505af1158015610e84573d6000803e3d6000fd5b5050506000828152600c6020526040902080546001600160a01b031916905550610eae838261117e565b60405181906001600160a01b038516907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f7590600090a350600101610db7565b5050506108bc6001600055565b6000610f0581610fa5565b6001600160a01b038216610f2c5760405163d92e233d60e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0384169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d190600090a25050565b6000610f8282611255565b6001600160a01b0383166000908152600960205260409020546106709190611339565b610faf81336112e6565b50565b600260005403610fd557604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b6000610fe782611255565b90508015611078576001600160a01b03821660009081526009602052604081208054839290611017908490611339565b90915550506001600160a01b038216600081815260096020526040908190205460055491517fca40132af767b10947fd7de6fe4074613c5850cc28b8d0aa94adb189bfb716be9261106f928252602082015260400190565b60405180910390a25b506005546001600160a01b03909116600090815260086020526040902055565b60006110a48383610bf5565b6111095760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a4506001610670565b506000610670565b600061111d8383610bf5565b156111095760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610670565b6001600160a01b0382166000908152600b60209081526040808320600d835281842085855290925282205481549192909183906111bd906001906115af565b815481106111cd576111cd611599565b90600052602060002001549050808383815481106111ed576111ed611599565b6000918252602080832091909101929092556001600160a01b0387168152600d82526040808220848352909252818120849055858152908120558254839080611238576112386115c2565b600190038181906000526020600020016000905590555050505050565b6001600160a01b03811660009081526007602052604081205480158061129557506001600160a01b03831660009081526008602052604090205460055411155b156112a35750600092915050565b6001600160a01b0383166000908152600860205260408120546005546112c991906115af565b90506112de8282670de0b6b3a7640000610619565b949350505050565b6112f08282610bf5565b6108bc5760405163e2517d3f60e01b81526001600160a01b03821660048201526024810183905260440160405180910390fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561067057610670611323565b60006020828403121561135e57600080fd5b81356001600160e01b03198116811461137657600080fd5b9392505050565b60006020828403121561138f57600080fd5b8135801515811461137657600080fd5b600080602083850312156113b257600080fd5b823567ffffffffffffffff8111156113c957600080fd5b8301601f810185136113da57600080fd5b803567ffffffffffffffff8111156113f157600080fd5b8560208260051b840101111561140657600080fd5b6020919091019590945092505050565b80356001600160a01b038116811461142d57600080fd5b919050565b60008060008060006080868803121561144a57600080fd5b61145386611416565b945061146160208701611416565b935060408601359250606086013567ffffffffffffffff81111561148457600080fd5b8601601f8101881361149557600080fd5b803567ffffffffffffffff8111156114ac57600080fd5b8860208284010111156114be57600080fd5b959894975092955050506020019190565b6000602082840312156114e157600080fd5b5035919050565b600080604083850312156114fb57600080fd5b8235915061150b60208401611416565b90509250929050565b60006020828403121561152657600080fd5b61137682611416565b602081526000608082018351602084015260208401516040840152604084015160608085015281815180845260a086019150602083019350600092505b8083101561158f578351825260208201915060208401935060018301925061156c565b5095945050505050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561067057610670611323565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220c1c13db05cbedfeb6655c613f26160f5202e6d488eebe36d9670c019b35e936f64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008ff243a318f02cad7efe5c2d950bd6d6388a2bf2000000000000000000000000ec3475f942ae76014997419fc69c20ce052b889f0000000000000000000000008ff243a318f02cad7efe5c2d950bd6d6388a2bf2
-----Decoded View---------------
Arg [0] : _deployer (address): 0x8ff243a318f02CAD7efE5c2d950bD6D6388A2BF2
Arg [1] : _initialAdmin (address): 0xEc3475f942AE76014997419fc69c20cE052B889f
Arg [2] : _treasury (address): 0x8ff243a318f02CAD7efE5c2d950bD6D6388A2BF2
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000008ff243a318f02cad7efe5c2d950bd6d6388a2bf2
Arg [1] : 000000000000000000000000ec3475f942ae76014997419fc69c20ce052b889f
Arg [2] : 0000000000000000000000008ff243a318f02cad7efe5c2d950bd6d6388a2bf2
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.