Source Code
Overview
ETH Balance
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 1 from a total of 1 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Init | 4238833 | 632 days ago | IN | 0 ETH | 0.00002104 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LockerToken
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 100000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {BaseLocker} from "./BaseLocker.sol";
contract LockerToken is BaseLocker {
function init(
address _token,
address _staking,
address _stakingBonus
) external initializer {
__BaseLocker_init(
"Locked ZERO Tokens",
"T-ZERO",
_token,
_staking,
_stakingBonus,
4 * 365 * 86400
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.20;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
abstract contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721, IERC721Metadata, IERC721Errors {
using Strings for uint256;
/// @custom:storage-location erc7201:openzeppelin.storage.ERC721
struct ERC721Storage {
// Token name
string _name;
// Token symbol
string _symbol;
mapping(uint256 tokenId => address) _owners;
mapping(address owner => uint256) _balances;
mapping(uint256 tokenId => address) _tokenApprovals;
mapping(address owner => mapping(address operator => bool)) _operatorApprovals;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC721")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC721StorageLocation = 0x80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079300;
function _getERC721Storage() private pure returns (ERC721Storage storage $) {
assembly {
$.slot := ERC721StorageLocation
}
}
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC721_init_unchained(name_, symbol_);
}
function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC721Storage storage $ = _getERC721Storage();
$._name = name_;
$._symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual returns (uint256) {
ERC721Storage storage $ = _getERC721Storage();
if (owner == address(0)) {
revert ERC721InvalidOwner(address(0));
}
return $._balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual returns (string memory) {
ERC721Storage storage $ = _getERC721Storage();
return $._name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual returns (string memory) {
ERC721Storage storage $ = _getERC721Storage();
return $._symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
_requireOwned(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual {
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual returns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
ERC721Storage storage $ = _getERC721Storage();
return $._operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
* core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
*/
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
return $._owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
return $._tokenApprovals[tokenId];
}
/**
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
* particular (ignoring whether it is owned by `owner`).
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
return
spender != address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
/**
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
* Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
* the `spender` for the specific `tokenId`.
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
*
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
* remain consistent with one another.
*/
function _increaseBalance(address account, uint128 value) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
unchecked {
$._balances[account] += value;
}
}
/**
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
*
* Emits a {Transfer} event.
*
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
ERC721Storage storage $ = _getERC721Storage();
address from = _ownerOf(tokenId);
// Perform (optional) operator check
if (auth != address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the update
if (from != address(0)) {
// Clear approval. No need to re-authorize or emit the Approval event
_approve(address(0), tokenId, address(0), false);
unchecked {
$._balances[from] -= 1;
}
}
if (to != address(0)) {
unchecked {
$._balances[to] += 1;
}
}
$._owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return from;
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner != address(0)) {
revert ERC721InvalidSender(address(0));
}
}
/**
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal {
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(address from, address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
* are aware of the ERC721 standard to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is like {safeTransferFrom} in the sense that it invokes
* {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `tokenId` token must exist and be owned by `from`.
* - `to` cannot be the zero address.
* - `from` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(address from, address to, uint256 tokenId) internal {
_safeTransfer(from, to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
* either the owner of the token, or approved to operate on all tokens held by this owner.
*
* Emits an {Approval} event.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address to, uint256 tokenId, address auth) internal {
_approve(to, tokenId, auth, true);
}
/**
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
* emitted in the context of transfers.
*/
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
// Avoid reading the owner unless necessary
if (emitEvent || auth != address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approve
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
$._tokenApprovals[tokenId] = to;
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Requirements:
* - operator can't be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
ERC721Storage storage $ = _getERC721Storage();
if (operator == address(0)) {
revert ERC721InvalidOperator(operator);
}
$._operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
* Returns the owner.
*
* Overrides to ownership logic should be done to {_ownerOf}.
*/
function _requireOwned(uint256 tokenId) internal view returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
* recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {ERC721Upgradeable} from "../ERC721Upgradeable.sol";
import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability
* of all the token ids in the contract as well as all token ids owned by each account.
*
* CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`,
* interfere with enumerability and should not be used together with `ERC721Enumerable`.
*/
abstract contract ERC721EnumerableUpgradeable is Initializable, ERC721Upgradeable, IERC721Enumerable {
/// @custom:storage-location erc7201:openzeppelin.storage.ERC721Enumerable
struct ERC721EnumerableStorage {
mapping(address owner => mapping(uint256 index => uint256)) _ownedTokens;
mapping(uint256 tokenId => uint256) _ownedTokensIndex;
uint256[] _allTokens;
mapping(uint256 tokenId => uint256) _allTokensIndex;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC721Enumerable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC721EnumerableStorageLocation = 0x645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed00;
function _getERC721EnumerableStorage() private pure returns (ERC721EnumerableStorage storage $) {
assembly {
$.slot := ERC721EnumerableStorageLocation
}
}
/**
* @dev An `owner`'s token query was out of bounds for `index`.
*
* NOTE: The owner being `address(0)` indicates a global out of bounds index.
*/
error ERC721OutOfBoundsIndex(address owner, uint256 index);
/**
* @dev Batch mint is not allowed.
*/
error ERC721EnumerableForbiddenBatchMint();
function __ERC721Enumerable_init() internal onlyInitializing {
}
function __ERC721Enumerable_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721Upgradeable) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
if (index >= balanceOf(owner)) {
revert ERC721OutOfBoundsIndex(owner, index);
}
return $._ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
return $._allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual returns (uint256) {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
if (index >= totalSupply()) {
revert ERC721OutOfBoundsIndex(address(0), index);
}
return $._allTokens[index];
}
/**
* @dev See {ERC721-_update}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
address previousOwner = super._update(to, tokenId, auth);
if (previousOwner == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_removeTokenFromOwnerEnumeration(previousOwner, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_addTokenToOwnerEnumeration(to, tokenId);
}
return previousOwner;
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
uint256 length = balanceOf(to) - 1;
$._ownedTokens[to][length] = tokenId;
$._ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
$._allTokensIndex[tokenId] = $._allTokens.length;
$._allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = balanceOf(from);
uint256 tokenIndex = $._ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = $._ownedTokens[from][lastTokenIndex];
$._ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
$._ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
delete $._ownedTokensIndex[tokenId];
delete $._ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
ERC721EnumerableStorage storage $ = _getERC721EnumerableStorage();
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = $._allTokens.length - 1;
uint256 tokenIndex = $._allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = $._allTokens[lastTokenIndex];
$._allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
$._allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete $._allTokensIndex[tokenId];
$._allTokens.pop();
}
/**
* See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch
*/
function _increaseBalance(address account, uint128 amount) internal virtual override {
if (amount > 0) {
revert ERC721EnumerableForbiddenBatchMint();
}
super._increaseBalance(account, amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @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.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// 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;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._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 {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// 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 {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// 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) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.20;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*/
interface IVotes {
/**
* @dev The signature used has expired.
*/
error VotesExpiredSignature(uint256 expiry);
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes);
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*/
function getPastVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) external view returns (address);
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) external;
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../token/ERC721/IERC721.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Receiver.sol)
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the 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.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.20;
// ███████╗███████╗██████╗ ██████╗
// ╚══███╔╝██╔════╝██╔══██╗██╔═══██╗
// ███╔╝ █████╗ ██████╔╝██║ ██║
// ███╔╝ ██╔══╝ ██╔══██╗██║ ██║
// ███████╗███████╗██║ ██║╚██████╔╝
// ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝
// Website: https://zerolend.xyz
// Discord: https://discord.gg/zerolend
// Twitter: https://twitter.com/zerolendxyz
import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol";
interface IOmnichainStaking is IVotes {
struct StakeInformation {
address owner;
uint256 tokenStake;
uint256 lpStake;
uint256 localVe;
}
// An omni-chain staking contract that allows users to stake their veNFT
// and get some voting power. Once staked the voting power is available cross-chain.
function unstakeLP(uint256 tokenId) external;
function unstakeToken(uint256 tokenId) external;
/// @dev using layerzero, sends the updated voting power across the different chains
function updatePowerOnChain(uint256 chainId, uint256 nftId) external;
/// @dev using layerzero, deletes the updated voting power across the different chains
function deletePowerOnChain(uint256 chainId, uint256 nftId) external;
/// @dev send the veStaked supply to the mainnet
function updateSupplyToMainnetViaLZ() external;
/// @dev receive the veStaked supply on the mainnet
function updateSupplyFromLZ() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol";
interface IZeroLocker is IERC721 {
function balanceOfNFT(uint256) external view returns (uint256);
function merge(uint256 _from, uint256 _to) external;
function depositFor(uint256 _tokenId, uint256 _value) external;
function createLockFor(
uint256 _value,
uint256 _lockDuration,
address _to,
bool _stakeNFT
) external returns (uint256);
function createLock(
uint256 _value,
uint256 _lockDuration,
bool _stakeNFT
) external returns (uint256);
enum DepositType {
DEPOSIT_FOR_TYPE,
CREATE_LOCK_TYPE,
INCREASE_LOCK_AMOUNT,
INCREASE_UNLOCK_TIME,
MERGE_TYPE
}
struct LockedBalance {
uint256 amount;
uint256 end;
uint256 start;
uint256 power;
}
event Deposit(
address indexed provider,
uint256 tokenId,
uint256 value,
uint256 indexed locktime,
DepositType deposit_type,
uint256 ts
);
event Withdraw(
address indexed provider,
uint256 tokenId,
uint256 value,
uint256 ts
);
event Supply(uint256 prevSupply, uint256 supply);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC165, ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {IZeroLocker} from "../interfaces/IZeroLocker.sol";
import {IOmnichainStaking} from "../interfaces/IOmnichainStaking.sol";
/**
@title Voting Escrow
@author Curve Finance
@notice Votes have a weight depending on time, so that users are
committed to the future of (whatever they are voting for)
@dev Vote weight decays linearly over time. Lock time cannot be
more than `MAXTIME` (4 years).
# Voting escrow to have time-weighted votes
# Votes have a weight depending on time, so that users are committed
# to the future of (whatever they are voting for).
# The weight in this implementation is linear, and lock cannot be more than maxtime:
# w ^
# 1 + /
# | /
# | /
# | /
# |/c
# 0 +--------+------> time
# maxtime (4 years?)
*/
contract BaseLocker is
ReentrancyGuardUpgradeable,
ERC721EnumerableUpgradeable,
IZeroLocker
{
uint256 internal WEEK;
uint256 internal MAXTIME;
uint256 internal MULTIPLIER;
uint256 public supply;
mapping(uint256 => LockedBalance) public locked;
string public version;
uint8 public decimals;
/// @dev Current count of token
uint256 internal tokenId;
IERC20 public underlying;
IOmnichainStaking public staking;
function __BaseLocker_init(
string memory _name,
string memory _symbol,
address _token,
address _staking,
address _stakingBonus,
uint256 _maxTime
) internal {
__ERC721_init(_name, _symbol);
__ReentrancyGuard_init();
version = "1.0.0";
decimals = 18;
WEEK = 1 weeks;
MAXTIME = _maxTime;
MULTIPLIER = 1 ether;
staking = IOmnichainStaking(_staking);
underlying = IERC20(_token);
_setApprovalForAll(address(this), _stakingBonus, true);
_setApprovalForAll(address(this), _staking, true);
}
/// @dev Interface identification is specified in ERC-165.
/// @param _interfaceID Id of the interface
function supportsInterface(
bytes4 _interfaceID
)
public
view
override(ERC721EnumerableUpgradeable, IERC165)
returns (bool)
{
return ERC721EnumerableUpgradeable.supportsInterface(_interfaceID);
}
/// @notice Get timestamp when `_tokenId`'s lock finishes
/// @param _tokenId User NFT
/// @return Epoch time of the lock end
function lockedEnd(uint256 _tokenId) external view returns (uint256) {
return locked[_tokenId].end;
}
/// @dev Returns the voting power of the `_owner`.
/// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid.
/// @param _owner Address for whom to query the voting power of.
function votingPowerOf(
address _owner
) external view returns (uint256 _power) {
for (uint256 index = 0; index < balanceOf(_owner); index++) {
uint256 _tokenId = tokenOfOwnerByIndex(_owner, index);
_power += balanceOfNFT(_tokenId);
}
}
function _calculatePower(
LockedBalance memory lock
) internal view returns (uint256) {
return ((lock.end - lock.start) * lock.amount) / MAXTIME;
}
/// @notice Deposit and lock tokens for a user
/// @param _tokenId NFT that holds lock
/// @param _value Amount to deposit
/// @param _unlockTime New time when to unlock the tokens, or 0 if unchanged
/// @param _lock Previous locked amount / timestamp
/// @param _type The type of deposit
function _depositFor(
uint256 _tokenId,
uint256 _value,
uint256 _unlockTime,
LockedBalance memory _lock,
DepositType _type
) internal {
LockedBalance memory lock = _lock;
uint256 supplyBefore = supply;
supply = supplyBefore + _value;
LockedBalance memory oldLocked;
(oldLocked.amount, oldLocked.end, oldLocked.power) = (
lock.amount,
lock.end,
lock.power
);
// Adding to existing lock, or if a lock is expired - creating a new one
lock.amount += _value;
if (_unlockTime != 0) lock.end = _unlockTime;
if (_type == DepositType.CREATE_LOCK_TYPE) lock.start = block.timestamp;
lock.power = _calculatePower(lock);
locked[_tokenId] = lock;
// Possibilities:
// Both oldLocked.end could be current or expired (>/< block.timestamp)
// value == 0 (extend lock) or value > 0 (add to lock or extend lock)
// _locked.end > block.timestamp (always)
if (_value != 0 && _type != DepositType.MERGE_TYPE)
assert(underlying.transferFrom(msg.sender, address(this), _value));
emit Deposit(
msg.sender,
_tokenId,
_value,
lock.end,
_type,
block.timestamp
);
emit Supply(supplyBefore, supplyBefore + _value);
}
function merge(uint256 _from, uint256 _to) external override {
require(_from != _to, "same nft");
require(
_isAuthorized(ownerOf(_from), msg.sender, _from),
"from not approved"
);
require(
_isAuthorized(ownerOf(_to), msg.sender, _to),
"to not approved"
);
LockedBalance memory _locked0 = locked[_from];
LockedBalance memory _locked1 = locked[_to];
uint256 value0 = uint256(int256(_locked0.amount));
uint256 end = _locked0.end >= _locked1.end
? _locked0.end
: _locked1.end;
locked[_from] = LockedBalance(0, 0, 0, 0);
_burn(_from);
_depositFor(_to, value0, end, _locked1, DepositType.MERGE_TYPE);
}
/// @notice Deposit `_value` tokens for `_tokenId` and add to the lock
/// @dev Anyone (even a smart contract) can deposit for someone else, but
/// cannot extend their locktime and deposit for a brand new user
/// @param _tokenId lock NFT
/// @param _value Amount to add to user's lock
function depositFor(
uint256 _tokenId,
uint256 _value
) external override nonReentrant {
LockedBalance memory _locked = locked[_tokenId];
require(_value > 0, "value = 0"); // dev: need non-zero value
require(_locked.amount > 0, "No existing lock found");
require(_locked.end > block.timestamp, "Cannot add to expired lock.");
_depositFor(_tokenId, _value, 0, _locked, DepositType.DEPOSIT_FOR_TYPE);
}
/// @notice Deposit `_value` tokens for `_to` and lock for `_lockDuration`
/// @param _value Amount to deposit
/// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week)
/// @param _to Address to deposit
function createLockFor(
uint256 _value,
uint256 _lockDuration,
address _to,
bool _stakeNFT
) external override nonReentrant returns (uint256) {
return _createLock(_value, _lockDuration, _to, _stakeNFT);
}
/// @notice Deposit `_value` tokens for `msg.sender` and lock for `_lockDuration`
/// @param _value Amount to deposit
/// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week)
/// @param _stakeNFT Should we also stake the NFT as well?
function createLock(
uint256 _value,
uint256 _lockDuration,
bool _stakeNFT
) external override nonReentrant returns (uint256) {
return _createLock(_value, _lockDuration, msg.sender, _stakeNFT);
}
/// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time
/// @param _value Amount of tokens to deposit and add to the lock
function increaseAmount(
uint256 _tokenId,
uint256 _value
) external nonReentrant {
require(
_isAuthorized(_ownerOf(_tokenId), msg.sender, _tokenId),
"caller is not owner nor approved"
);
LockedBalance memory _locked = locked[_tokenId];
assert(_value > 0); // dev: need non-zero value
require(_locked.amount > 0, "No existing lock found");
require(_locked.end > block.timestamp, "Cannot add to expired lock.");
_depositFor(
_tokenId,
_value,
0,
_locked,
DepositType.INCREASE_LOCK_AMOUNT
);
}
/// @notice Extend the unlock time for `_tokenId`
/// @param _lockDuration New number of seconds until tokens unlock
function increaseUnlockTime(
uint256 _tokenId,
uint256 _lockDuration
) external nonReentrant {
require(
_isAuthorized(ownerOf(_tokenId), msg.sender, _tokenId),
"caller is not owner nor approved"
);
LockedBalance memory _locked = locked[_tokenId];
uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
require(_locked.end > block.timestamp, "Lock expired");
require(_locked.amount > 0, "Nothing is locked");
require(unlockTime > _locked.end, "Can only increase lock duration");
require(
unlockTime <= block.timestamp + MAXTIME,
"Voting lock can be 4 years max"
);
require(
unlockTime <= _locked.start + MAXTIME,
"Voting lock can be 4 years max"
);
_depositFor(
_tokenId,
0,
unlockTime,
_locked,
DepositType.INCREASE_UNLOCK_TIME
);
}
/// @notice Withdraw all tokens for `_tokenId`
/// @dev Only possible if the lock has expired
function withdraw(uint256 _tokenId) public nonReentrant {
require(
_isAuthorized(ownerOf(_tokenId), msg.sender, _tokenId),
"caller is not owner nor approved"
);
LockedBalance memory _locked = locked[_tokenId];
require(block.timestamp >= _locked.end, "The lock didn't expire");
uint256 value = uint256(int256(_locked.amount));
locked[_tokenId] = LockedBalance(0, 0, 0, 0);
uint256 supplyBefore = supply;
supply = supplyBefore - value;
assert(underlying.transfer(msg.sender, value));
// Burn the NFT
_burn(_tokenId);
emit Withdraw(msg.sender, _tokenId, value, block.timestamp);
emit Supply(supplyBefore, supplyBefore - value);
}
function withdraw(uint256[] calldata _tokenIds) external nonReentrant {
uint256 nftCount = _tokenIds.length;
for (uint i = 0; i < nftCount; ) {
withdraw(_tokenIds[i]);
unchecked {
++i;
}
}
}
function withdraw(address _user) external nonReentrant {
uint256 nftCount = balanceOf(_user);
for (uint i = 0; i < nftCount; ) {
uint256 tokenId_ = tokenOfOwnerByIndex(_user, i);
withdraw(tokenId_);
unchecked {
++i;
}
}
}
/// @notice Deposit `_value` tokens for `_to` and lock for `_lockDuration`
/// @param _value Amount to deposit
/// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week)
/// @param _to Address to deposit
/// @param _stakeNFT should we stake into the staking contract
function _createLock(
uint256 _value,
uint256 _lockDuration,
address _to,
bool _stakeNFT
) internal returns (uint256) {
uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
require(_value > 0, "value = 0"); // dev: need non-zero value
require(unlockTime > block.timestamp, "Can only lock in the future");
require(
unlockTime <= block.timestamp + MAXTIME,
"Voting lock can be 4 years max"
);
++tokenId;
uint256 _tokenId = tokenId;
_depositFor(
_tokenId,
_value,
unlockTime,
locked[_tokenId],
DepositType.CREATE_LOCK_TYPE
);
// if the user wants to stake the NFT then we mint to the contract and
// stake on behalf of the user
if (_stakeNFT) {
_mint(address(this), _tokenId);
bytes memory data = abi.encode(_stakeNFT, _to, _lockDuration);
this.safeTransferFrom(
address(this),
address(staking),
_tokenId,
data
);
} else _mint(_to, _tokenId);
return _tokenId;
}
function balanceOfNFT(uint256 _tokenId) public view returns (uint256) {
return locked[_tokenId].power;
}
function tokenURI(
uint256
) public view virtual override returns (string memory) {
// todo
return "";
}
}{
"optimizer": {
"enabled": true,
"runs": 100000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"ERC721EnumerableForbiddenBatchMint","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC721OutOfBoundsIndex","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"locktime","type":"uint256"},{"indexed":false,"internalType":"enum IZeroLocker.DepositType","name":"deposit_type","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"}],"name":"Supply","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"balanceOfNFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"bool","name":"_stakeNFT","type":"bool"}],"name":"createLock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"bool","name":"_stakeNFT","type":"bool"}],"name":"createLockFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"increaseAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"}],"name":"increaseUnlockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_staking","type":"address"},{"internalType":"address","name":"_stakingBonus","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"locked","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"lockedEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"merge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"staking","outputs":[{"internalType":"contract IOmnichainStaking","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"votingPowerOf","outputs":[{"internalType":"uint256","name":"_power","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50613ab4806100206000396000f3fe608060405234801561001057600080fd5b50600436106102415760003560e01c806354fd4d5011610145578063b2383e55116100bd578063c87b56dd1161008c578063d60371a711610071578063d60371a71461056c578063e7e242d41461057f578063e985e9c5146105a257600080fd5b8063c87b56dd14610538578063d1c2babb1461055957600080fd5b8063b2383e55146104aa578063b45a3c0e146104bd578063b88d4fde14610512578063bcc3f3bd1461052557600080fd5b806370a0823111610114578063983d95ce116100f9578063983d95ce146104715780639d507b8b14610484578063a22cb4651461049757600080fd5b806370a082311461045657806395d89b411461046957600080fd5b806354fd4d50146103f8578063626944df146104005780636352211e146104235780636f307dc31461043657600080fd5b8063184b9559116101d8578063313ce567116101a75780634cf088d91161018c5780634cf088d9146103b25780634f6ccce7146103d257806351cff8d9146103e557600080fd5b8063313ce5671461038057806342842e0e1461039f57600080fd5b8063184b95591461033457806323b872dd146103475780632e1a7d4d1461035a5780632f745c591461036d57600080fd5b8063095ea7b311610214578063095ea7b3146102d25780630a2abdb3146102e75780630ec84dda146102fa57806318160ddd1461030d57600080fd5b806301ffc9a714610246578063047fc9aa1461026e57806306fdde0314610285578063081812fc1461029a575b600080fd5b610259610254366004613213565b61060a565b60405190151581526020015b60405180910390f35b61027760035481565b604051908152602001610265565b61028d61061b565b6040516102659190613294565b6102ad6102a83660046132a7565b6106d1565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b6102e56102e03660046132e9565b610726565b005b6102776102f5366004613321565b610735565b6102e5610308366004613369565b61077e565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0254610277565b6102e561034236600461338b565b610941565b6102e56103553660046133ce565b610b37565b6102e56103683660046132a7565b610c28565b61027761037b3660046132e9565b610f0f565b60065461038d9060ff1681565b60405160ff9091168152602001610265565b6102e56103ad3660046133ce565b610fc8565b6009546102ad9073ffffffffffffffffffffffffffffffffffffffff1681565b6102776103e03660046132a7565b610fe8565b6102e56103f336600461340a565b61109d565b61028d611108565b61027761040e3660046132a7565b60009081526004602052604090206001015490565b6102ad6104313660046132a7565b611196565b6008546102ad9073ffffffffffffffffffffffffffffffffffffffff1681565b61027761046436600461340a565b6111a1565b61028d611242565b6102e561047f366004613425565b611293565b6102e5610492366004613369565b6112fb565b6102e56104a536600461349a565b611622565b6102e56104b8366004613369565b61162d565b6104f26104cb3660046132a7565b60046020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610265565b6102e5610520366004613500565b61181a565b61027761053336600461340a565b611831565b61028d6105463660046132a7565b5060408051602081019091526000815290565b6102e5610567366004613369565b61188c565b61027761057a3660046135fa565b611adc565b61027761058d3660046132a7565b60009081526004602052604090206003015490565b6102596105b0366004613633565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793056020908152604080832093909416825291909152205460ff1690565b600061061582611b24565b92915050565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079300805460609190819061064d90613666565b80601f016020809104026020016040519081016040528092919081815260200182805461067990613666565b80156106c65780601f1061069b576101008083540402835291602001916106c6565b820191906000526020600020905b8154815290600101906020018083116106a957829003601f168201915b505050505091505090565b60006106dc82611b7a565b5060008281527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079304602052604090205473ffffffffffffffffffffffffffffffffffffffff16610615565b610731828233611bf8565b5050565b600061073f611c05565b61074b85858585611c86565b905061077660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b949350505050565b610786611c05565b600082815260046020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015281610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f76616c7565203d2030000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b805161089b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e6400000000000000000000604482015260640161082a565b42816020015111610908576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e0000000000604482015260640161082a565b61091783836000846000611f64565b5061073160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561098c5750825b905060008267ffffffffffffffff1660011480156109a95750303b155b9050811580156109b7575080155b156109ee576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610a4f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610acb6040518060400160405280601281526020017f4c6f636b6564205a45524f20546f6b656e7300000000000000000000000000008152506040518060400160405280600681526020017f542d5a45524f00000000000000000000000000000000000000000000000000008152508a8a8a630784ce006121ab565b8315610b2d5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2906020015b60405180910390a15b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8216610b87576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b6000610b948383336122af565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610c22576040517f64283d7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8086166004830152602482018490528216604482015260640161082a565b50505050565b610c30611c05565b610c43610c3c82611196565b3383612408565b610ca9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564604482015260640161082a565b6000818152600460209081526040918290208251608081018452815481526001820154928101839052600282015493810193909352600301546060830152421015610d50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f546865206c6f636b206469646e27742065787069726500000000000000000000604482015260640161082a565b8051604080516080810182526000808252602080830182815283850183815260608501848152898552600490935294909220925183559051600183015591516002820155905160039182015554610da782826136e2565b6003556008546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810184905273ffffffffffffffffffffffffffffffffffffffff9091169063a9059cbb906044016020604051808303816000875af1158015610e21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4591906136f5565b610e5157610e51613712565b610e5a8461250a565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c81610ec884826136e2565b6040805192835260208301919091520160405180910390a1505050610f0c60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50565b60007f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed00610f3b846111a1565b8310610f92576040517fa57d13dc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024810184905260440161082a565b73ffffffffffffffffffffffffffffffffffffffff84166000908152602091825260408082208583529092522054905092915050565b610fe38383836040518060200160405280600081525061181a565b505050565b60007f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed006110337f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed025490565b8310611075576040517fa57d13dc000000000000000000000000000000000000000000000000000000008152600060048201526024810184905260440161082a565b80600201838154811061108a5761108a613741565b9060005260206000200154915050919050565b6110a5611c05565b60006110b0826111a1565b905060005b818110156110dd5760006110c98483610f0f565b90506110d481610c28565b506001016110b5565b5050610f0c60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6005805461111590613666565b80601f016020809104026020016040519081016040528092919081815260200182805461114190613666565b801561118e5780601f106111635761010080835404028352916020019161118e565b820191906000526020600020905b81548152906001019060200180831161117157829003601f168201915b505050505081565b600061061582611b7a565b60007f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930073ffffffffffffffffffffffffffffffffffffffff8316611214576040517f89c62b640000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b73ffffffffffffffffffffffffffffffffffffffff9092166000908152600390920160205250604090205490565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930180546060917f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793009161064d90613666565b61129b611c05565b8060005b818110156112d0576112c88484838181106112bc576112bc613741565b90506020020135610c28565b60010161129f565b505061073160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611303611c05565b61131661130f83611196565b3384612408565b61137c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564604482015260640161082a565b60008281526004602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201528154909190806113ca8542613770565b6113d49190613783565b6113de91906137be565b90504282602001511161144d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4c6f636b20657870697265640000000000000000000000000000000000000000604482015260640161082a565b81516114b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e6f7468696e67206973206c6f636b6564000000000000000000000000000000604482015260640161082a565b81602001518111611522576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e00604482015260640161082a565b60015461152f9042613770565b811115611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d61780000604482015260640161082a565b60015482604001516115aa9190613770565b811115611613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d61780000604482015260640161082a565b6112d084600083856003611f64565b61073133838361256b565b611635611c05565b60008281527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930260205260409020546116829073ffffffffffffffffffffffffffffffffffffffff1661130f565b6116e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564604482015260640161082a565b60008281526004602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460608201528161173657611736613712565b805161179e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e6400000000000000000000604482015260640161082a565b4281602001511161180b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e0000000000604482015260640161082a565b61091783836000846002611f64565b611825848484610b37565b610c228484848461268c565b6000805b61183e836111a1565b8110156118865760006118518483610f0f565b6000818152600460205260409020600301549091506118709084613770565b925050808061187e906137d5565b915050611835565b50919050565b8082036118f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f73616d65206e6674000000000000000000000000000000000000000000000000604482015260640161082a565b61190161130f83611196565b611967576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f66726f6d206e6f7420617070726f766564000000000000000000000000000000604482015260640161082a565b611973610c3c82611196565b6119d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f746f206e6f7420617070726f7665640000000000000000000000000000000000604482015260640161082a565b600082815260046020818152604080842081516080808201845282548252600180840154838701908152600280860154858801526003958601546060808701919091528b8b52988852868a208751948501885280548552928301549784018890528201549583019590955290920154948201949094528351915193949093919290911015611a6b578260200151611a71565b83602001515b6040805160808101825260008082526020808301828152838501838152606085018481528d855260049093529490922092518355905160018301559151600282015590516003909101559050611ac68661250a565b611ad4858383866004611f64565b505050505050565b6000611ae6611c05565b611af284843385611c86565b9050611b1d60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b9392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d63000000000000000000000000000000000000000000000000000000001480610615575061061582612883565b60008181527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079302602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610615576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810184905260240161082a565b610fe38383836001612966565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01611c80576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b60008054819080611c978742613770565b611ca19190613783565b611cab91906137be565b905060008611611d17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f76616c7565203d20300000000000000000000000000000000000000000000000604482015260640161082a565b428111611d80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f43616e206f6e6c79206c6f636b20696e20746865206675747572650000000000604482015260640161082a565b600154611d8d9042613770565b811115611df6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d61780000604482015260640161082a565b600760008154611e05906137d5565b9091555060075460008181526004602090815260409182902082516080810184528154815260018083015493820193909352600282015493810193909352600301546060830152611e5b9183918a918691611f64565b8315611f2a57611e6b3082612b72565b60408051851515602082015273ffffffffffffffffffffffffffffffffffffffff8781168284015260608083018a90528351808403909101815260808301938490526009547fb88d4fde0000000000000000000000000000000000000000000000000000000090945292309263b88d4fde92611ef29285929116908790879060840161380d565b600060405180830381600087803b158015611f0c57600080fd5b505af1158015611f20573d6000803e3d6000fd5b5050505050611f34565b611f348582612b72565b9695505050505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6003548290611f738682613770565b600381905550611fa46040518060800160405280600081526020016000815260200160008152602001600081525090565b825160208085015160608087015190850152908301528152825187908490611fcd908390613770565b9052508515611fde57602083018690525b6001846004811115611ff257611ff261384c565b03611ffe574260408401525b61200783612c23565b60608401908152600089815260046020908152604091829020865181559086015160018201559085015160028201559051600390910155861580159061205f5750600484600481111561205c5761205c61384c565b14155b15612111576008546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810189905273ffffffffffffffffffffffffffffffffffffffff909116906323b872dd906064016020604051808303816000875af11580156120e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210591906136f5565b61211157612111613712565b82602001513373ffffffffffffffffffffffffffffffffffffffff167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248a8a8842604051612162949392919061387b565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c826121968982613770565b60408051928352602083019190915201610b24565b6121b58686612c55565b6121bd612c67565b6040805180820190915260058082527f312e302e300000000000000000000000000000000000000000000000000000006020830152906121fd9082613918565b50600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016601217905562093a806000556001818155670de0b6b3a76400006002556009805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560088054928816929091169190911790556122a3903090849061256b565b611ad43084600161256b565b6000806122bd858585612c79565b905073ffffffffffffffffffffffffffffffffffffffff811661236557612360847f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed02805460008381527f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0360205260408120829055600182018355919091527fa42f15e5d656f8155fd7419d740a6073999f19cd6e061449ce4a257150545bf20155565b6123a2565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146123a2576123a28185612e3e565b73ffffffffffffffffffffffffffffffffffffffff85166123cb576123c684612f0e565b610776565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610776576107768585613009565b600073ffffffffffffffffffffffffffffffffffffffff83161580159061077657508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806124b5575073ffffffffffffffffffffffffffffffffffffffff80851660009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079305602090815260408083209387168352929052205460ff165b8061077657505060009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079304602052604090205473ffffffffffffffffffffffffffffffffffffffff908116911614919050565b600061251960008360006122af565b905073ffffffffffffffffffffffffffffffffffffffff8116610731576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810183905260240161082a565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930073ffffffffffffffffffffffffffffffffffffffff83166125f1576040517f5b08ba1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161082a565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260058401602090815260408083209488168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b73ffffffffffffffffffffffffffffffffffffffff83163b15610c22576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063150b7a029061270190339088908790879060040161380d565b6020604051808303816000875af192505050801561275a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261275791810190613a32565b60015b6127e9573d808015612788576040519150601f19603f3d011682016040523d82523d6000602084013e61278d565b606091505b5080516000036127e1576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161082a565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a02000000000000000000000000000000000000000000000000000000001461287c576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161082a565b5050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061291657507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061061557507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610615565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930081806129a8575073ffffffffffffffffffffffffffffffffffffffff831615155b15612b1c5760006129b885611b7a565b905073ffffffffffffffffffffffffffffffffffffffff841615801590612a0b57508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015612a69575073ffffffffffffffffffffffffffffffffffffffff80821660009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079305602090815260408083209388168352929052205460ff16155b15612ab8576040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161082a565b8215612b1a57848673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b600093845260040160205250506040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff8216612bc2576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b6000612bd0838360006122af565b905073ffffffffffffffffffffffffffffffffffffffff811615610fe3576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b6000600154826000015183604001518460200151612c4191906136e2565b612c4b91906137be565b6106159190613783565b612c5d613083565b61073182826130ea565b612c6f613083565b612c7761312d565b565b60008281527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930260205260408120547f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793009073ffffffffffffffffffffffffffffffffffffffff90811690841615612cf457612cf4818587613135565b73ffffffffffffffffffffffffffffffffffffffff811615612d6c57612d1e600086600080612966565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600383016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555b73ffffffffffffffffffffffffffffffffffffffff861615612db75773ffffffffffffffffffffffffffffffffffffffff861660009081526003830160205260409020805460010190555b600085815260028301602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a811691821790925591518893918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a495945050505050565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed006000612e6a846111a1565b6000848152600184016020526040902054909150808214612ecc5773ffffffffffffffffffffffffffffffffffffffff851660009081526020848152604080832085845282528083205484845281842081905583526001860190915290208190555b506000928352600182016020908152604080852085905573ffffffffffffffffffffffffffffffffffffffff9095168452918252838320908352905290812055565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed02547f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0090600090612f61906001906136e2565b6000848152600384016020526040812054600285018054939450909284908110612f8d57612f8d613741565b9060005260206000200154905080846002018381548110612fb057612fb0613741565b600091825260208083209091019290925582815260038601909152604080822084905586825281205560028401805480612fec57612fec613a4f565b600190038181906000526020600020016000905590555050505050565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0060006001613037856111a1565b61304191906136e2565b73ffffffffffffffffffffffffffffffffffffffff90941660009081526020838152604080832087845282528083208690559482526001909301909252502055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16612c77576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130f2613083565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793008061311e8482613918565b5060018101610c228382613918565b611f3e613083565b613140838383612408565b610fe35773ffffffffffffffffffffffffffffffffffffffff8316613194576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810182905260240161082a565b6040517f177e802f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024810182905260440161082a565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610f0c57600080fd5b60006020828403121561322557600080fd5b8135611b1d816131e5565b6000815180845260005b818110156132565760208185018101518683018201520161323a565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611b1d6020830184613230565b6000602082840312156132b957600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146132e457600080fd5b919050565b600080604083850312156132fc57600080fd5b613305836132c0565b946020939093013593505050565b8015158114610f0c57600080fd5b6000806000806080858703121561333757600080fd5b843593506020850135925061334e604086016132c0565b9150606085013561335e81613313565b939692955090935050565b6000806040838503121561337c57600080fd5b50508035926020909101359150565b6000806000606084860312156133a057600080fd5b6133a9846132c0565b92506133b7602085016132c0565b91506133c5604085016132c0565b90509250925092565b6000806000606084860312156133e357600080fd5b6133ec846132c0565b92506133fa602085016132c0565b9150604084013590509250925092565b60006020828403121561341c57600080fd5b611b1d826132c0565b6000806020838503121561343857600080fd5b823567ffffffffffffffff8082111561345057600080fd5b818501915085601f83011261346457600080fd5b81358181111561347357600080fd5b8660208260051b850101111561348857600080fd5b60209290920196919550909350505050565b600080604083850312156134ad57600080fd5b6134b6836132c0565b915060208301356134c681613313565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000806080858703121561351657600080fd5b61351f856132c0565b935061352d602086016132c0565b925060408501359150606085013567ffffffffffffffff8082111561355157600080fd5b818701915087601f83011261356557600080fd5b813581811115613577576135776134d1565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135bd576135bd6134d1565b816040528281528a60208487010111156135d657600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060006060848603121561360f57600080fd5b8335925060208401359150604084013561362881613313565b809150509250925092565b6000806040838503121561364657600080fd5b61364f836132c0565b915061365d602084016132c0565b90509250929050565b600181811c9082168061367a57607f821691505b602082108103611886577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610615576106156136b3565b60006020828403121561370757600080fd5b8151611b1d81613313565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80820180821115610615576106156136b3565b6000826137b9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8082028115828204841417610615576106156136b3565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613806576138066136b3565b5060010190565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152611f346080830184613230565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8481526020810184905260808101600584106138c0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60408201939093526060015292915050565b601f821115610fe357600081815260208120601f850160051c810160208610156138f95750805b601f850160051c820191505b81811015611ad457828155600101613905565b815167ffffffffffffffff811115613932576139326134d1565b613946816139408454613666565b846138d2565b602080601f83116001811461399957600084156139635750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611ad4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156139e6578886015182559484019460019091019084016139c7565b5085821015613a2257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613a4457600080fd5b8151611b1d816131e5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220f2be9ef63c8cff84424c4cc6ce88dc4fafa26cc588aa7e368cdf7698ca087d6564736f6c63430008140033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102415760003560e01c806354fd4d5011610145578063b2383e55116100bd578063c87b56dd1161008c578063d60371a711610071578063d60371a71461056c578063e7e242d41461057f578063e985e9c5146105a257600080fd5b8063c87b56dd14610538578063d1c2babb1461055957600080fd5b8063b2383e55146104aa578063b45a3c0e146104bd578063b88d4fde14610512578063bcc3f3bd1461052557600080fd5b806370a0823111610114578063983d95ce116100f9578063983d95ce146104715780639d507b8b14610484578063a22cb4651461049757600080fd5b806370a082311461045657806395d89b411461046957600080fd5b806354fd4d50146103f8578063626944df146104005780636352211e146104235780636f307dc31461043657600080fd5b8063184b9559116101d8578063313ce567116101a75780634cf088d91161018c5780634cf088d9146103b25780634f6ccce7146103d257806351cff8d9146103e557600080fd5b8063313ce5671461038057806342842e0e1461039f57600080fd5b8063184b95591461033457806323b872dd146103475780632e1a7d4d1461035a5780632f745c591461036d57600080fd5b8063095ea7b311610214578063095ea7b3146102d25780630a2abdb3146102e75780630ec84dda146102fa57806318160ddd1461030d57600080fd5b806301ffc9a714610246578063047fc9aa1461026e57806306fdde0314610285578063081812fc1461029a575b600080fd5b610259610254366004613213565b61060a565b60405190151581526020015b60405180910390f35b61027760035481565b604051908152602001610265565b61028d61061b565b6040516102659190613294565b6102ad6102a83660046132a7565b6106d1565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b6102e56102e03660046132e9565b610726565b005b6102776102f5366004613321565b610735565b6102e5610308366004613369565b61077e565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0254610277565b6102e561034236600461338b565b610941565b6102e56103553660046133ce565b610b37565b6102e56103683660046132a7565b610c28565b61027761037b3660046132e9565b610f0f565b60065461038d9060ff1681565b60405160ff9091168152602001610265565b6102e56103ad3660046133ce565b610fc8565b6009546102ad9073ffffffffffffffffffffffffffffffffffffffff1681565b6102776103e03660046132a7565b610fe8565b6102e56103f336600461340a565b61109d565b61028d611108565b61027761040e3660046132a7565b60009081526004602052604090206001015490565b6102ad6104313660046132a7565b611196565b6008546102ad9073ffffffffffffffffffffffffffffffffffffffff1681565b61027761046436600461340a565b6111a1565b61028d611242565b6102e561047f366004613425565b611293565b6102e5610492366004613369565b6112fb565b6102e56104a536600461349a565b611622565b6102e56104b8366004613369565b61162d565b6104f26104cb3660046132a7565b60046020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610265565b6102e5610520366004613500565b61181a565b61027761053336600461340a565b611831565b61028d6105463660046132a7565b5060408051602081019091526000815290565b6102e5610567366004613369565b61188c565b61027761057a3660046135fa565b611adc565b61027761058d3660046132a7565b60009081526004602052604090206003015490565b6102596105b0366004613633565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793056020908152604080832093909416825291909152205460ff1690565b600061061582611b24565b92915050565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079300805460609190819061064d90613666565b80601f016020809104026020016040519081016040528092919081815260200182805461067990613666565b80156106c65780601f1061069b576101008083540402835291602001916106c6565b820191906000526020600020905b8154815290600101906020018083116106a957829003601f168201915b505050505091505090565b60006106dc82611b7a565b5060008281527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079304602052604090205473ffffffffffffffffffffffffffffffffffffffff16610615565b610731828233611bf8565b5050565b600061073f611c05565b61074b85858585611c86565b905061077660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b949350505050565b610786611c05565b600082815260046020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015281610833576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f76616c7565203d2030000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b805161089b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e6400000000000000000000604482015260640161082a565b42816020015111610908576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e0000000000604482015260640161082a565b61091783836000846000611f64565b5061073160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561098c5750825b905060008267ffffffffffffffff1660011480156109a95750303b155b9050811580156109b7575080155b156109ee576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610a4f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610acb6040518060400160405280601281526020017f4c6f636b6564205a45524f20546f6b656e7300000000000000000000000000008152506040518060400160405280600681526020017f542d5a45524f00000000000000000000000000000000000000000000000000008152508a8a8a630784ce006121ab565b8315610b2d5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2906020015b60405180910390a15b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8216610b87576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b6000610b948383336122af565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610c22576040517f64283d7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8086166004830152602482018490528216604482015260640161082a565b50505050565b610c30611c05565b610c43610c3c82611196565b3383612408565b610ca9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564604482015260640161082a565b6000818152600460209081526040918290208251608081018452815481526001820154928101839052600282015493810193909352600301546060830152421015610d50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f546865206c6f636b206469646e27742065787069726500000000000000000000604482015260640161082a565b8051604080516080810182526000808252602080830182815283850183815260608501848152898552600490935294909220925183559051600183015591516002820155905160039182015554610da782826136e2565b6003556008546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810184905273ffffffffffffffffffffffffffffffffffffffff9091169063a9059cbb906044016020604051808303816000875af1158015610e21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4591906136f5565b610e5157610e51613712565b610e5a8461250a565b60408051858152602081018490524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c81610ec884826136e2565b6040805192835260208301919091520160405180910390a1505050610f0c60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50565b60007f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed00610f3b846111a1565b8310610f92576040517fa57d13dc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024810184905260440161082a565b73ffffffffffffffffffffffffffffffffffffffff84166000908152602091825260408082208583529092522054905092915050565b610fe38383836040518060200160405280600081525061181a565b505050565b60007f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed006110337f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed025490565b8310611075576040517fa57d13dc000000000000000000000000000000000000000000000000000000008152600060048201526024810184905260440161082a565b80600201838154811061108a5761108a613741565b9060005260206000200154915050919050565b6110a5611c05565b60006110b0826111a1565b905060005b818110156110dd5760006110c98483610f0f565b90506110d481610c28565b506001016110b5565b5050610f0c60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6005805461111590613666565b80601f016020809104026020016040519081016040528092919081815260200182805461114190613666565b801561118e5780601f106111635761010080835404028352916020019161118e565b820191906000526020600020905b81548152906001019060200180831161117157829003601f168201915b505050505081565b600061061582611b7a565b60007f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930073ffffffffffffffffffffffffffffffffffffffff8316611214576040517f89c62b640000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b73ffffffffffffffffffffffffffffffffffffffff9092166000908152600390920160205250604090205490565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930180546060917f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793009161064d90613666565b61129b611c05565b8060005b818110156112d0576112c88484838181106112bc576112bc613741565b90506020020135610c28565b60010161129f565b505061073160017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611303611c05565b61131661130f83611196565b3384612408565b61137c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564604482015260640161082a565b60008281526004602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201528154909190806113ca8542613770565b6113d49190613783565b6113de91906137be565b90504282602001511161144d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4c6f636b20657870697265640000000000000000000000000000000000000000604482015260640161082a565b81516114b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e6f7468696e67206973206c6f636b6564000000000000000000000000000000604482015260640161082a565b81602001518111611522576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e00604482015260640161082a565b60015461152f9042613770565b811115611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d61780000604482015260640161082a565b60015482604001516115aa9190613770565b811115611613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d61780000604482015260640161082a565b6112d084600083856003611f64565b61073133838361256b565b611635611c05565b60008281527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930260205260409020546116829073ffffffffffffffffffffffffffffffffffffffff1661130f565b6116e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564604482015260640161082a565b60008281526004602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460608201528161173657611736613712565b805161179e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f206578697374696e67206c6f636b20666f756e6400000000000000000000604482015260640161082a565b4281602001511161180b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f43616e6e6f742061646420746f2065787069726564206c6f636b2e0000000000604482015260640161082a565b61091783836000846002611f64565b611825848484610b37565b610c228484848461268c565b6000805b61183e836111a1565b8110156118865760006118518483610f0f565b6000818152600460205260409020600301549091506118709084613770565b925050808061187e906137d5565b915050611835565b50919050565b8082036118f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f73616d65206e6674000000000000000000000000000000000000000000000000604482015260640161082a565b61190161130f83611196565b611967576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f66726f6d206e6f7420617070726f766564000000000000000000000000000000604482015260640161082a565b611973610c3c82611196565b6119d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f746f206e6f7420617070726f7665640000000000000000000000000000000000604482015260640161082a565b600082815260046020818152604080842081516080808201845282548252600180840154838701908152600280860154858801526003958601546060808701919091528b8b52988852868a208751948501885280548552928301549784018890528201549583019590955290920154948201949094528351915193949093919290911015611a6b578260200151611a71565b83602001515b6040805160808101825260008082526020808301828152838501838152606085018481528d855260049093529490922092518355905160018301559151600282015590516003909101559050611ac68661250a565b611ad4858383866004611f64565b505050505050565b6000611ae6611c05565b611af284843385611c86565b9050611b1d60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b9392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d63000000000000000000000000000000000000000000000000000000001480610615575061061582612883565b60008181527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079302602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610615576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810184905260240161082a565b610fe38383836001612966565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01611c80576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b60008054819080611c978742613770565b611ca19190613783565b611cab91906137be565b905060008611611d17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f76616c7565203d20300000000000000000000000000000000000000000000000604482015260640161082a565b428111611d80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f43616e206f6e6c79206c6f636b20696e20746865206675747572650000000000604482015260640161082a565b600154611d8d9042613770565b811115611df6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f566f74696e67206c6f636b2063616e2062652034207965617273206d61780000604482015260640161082a565b600760008154611e05906137d5565b9091555060075460008181526004602090815260409182902082516080810184528154815260018083015493820193909352600282015493810193909352600301546060830152611e5b9183918a918691611f64565b8315611f2a57611e6b3082612b72565b60408051851515602082015273ffffffffffffffffffffffffffffffffffffffff8781168284015260608083018a90528351808403909101815260808301938490526009547fb88d4fde0000000000000000000000000000000000000000000000000000000090945292309263b88d4fde92611ef29285929116908790879060840161380d565b600060405180830381600087803b158015611f0c57600080fd5b505af1158015611f20573d6000803e3d6000fd5b5050505050611f34565b611f348582612b72565b9695505050505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6003548290611f738682613770565b600381905550611fa46040518060800160405280600081526020016000815260200160008152602001600081525090565b825160208085015160608087015190850152908301528152825187908490611fcd908390613770565b9052508515611fde57602083018690525b6001846004811115611ff257611ff261384c565b03611ffe574260408401525b61200783612c23565b60608401908152600089815260046020908152604091829020865181559086015160018201559085015160028201559051600390910155861580159061205f5750600484600481111561205c5761205c61384c565b14155b15612111576008546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810189905273ffffffffffffffffffffffffffffffffffffffff909116906323b872dd906064016020604051808303816000875af11580156120e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210591906136f5565b61211157612111613712565b82602001513373ffffffffffffffffffffffffffffffffffffffff167fff04ccafc360e16b67d682d17bd9503c4c6b9a131f6be6325762dc9ffc7de6248a8a8842604051612162949392919061387b565b60405180910390a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c826121968982613770565b60408051928352602083019190915201610b24565b6121b58686612c55565b6121bd612c67565b6040805180820190915260058082527f312e302e300000000000000000000000000000000000000000000000000000006020830152906121fd9082613918565b50600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016601217905562093a806000556001818155670de0b6b3a76400006002556009805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560088054928816929091169190911790556122a3903090849061256b565b611ad43084600161256b565b6000806122bd858585612c79565b905073ffffffffffffffffffffffffffffffffffffffff811661236557612360847f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed02805460008381527f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0360205260408120829055600182018355919091527fa42f15e5d656f8155fd7419d740a6073999f19cd6e061449ce4a257150545bf20155565b6123a2565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146123a2576123a28185612e3e565b73ffffffffffffffffffffffffffffffffffffffff85166123cb576123c684612f0e565b610776565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610776576107768585613009565b600073ffffffffffffffffffffffffffffffffffffffff83161580159061077657508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806124b5575073ffffffffffffffffffffffffffffffffffffffff80851660009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079305602090815260408083209387168352929052205460ff165b8061077657505060009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079304602052604090205473ffffffffffffffffffffffffffffffffffffffff908116911614919050565b600061251960008360006122af565b905073ffffffffffffffffffffffffffffffffffffffff8116610731576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810183905260240161082a565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930073ffffffffffffffffffffffffffffffffffffffff83166125f1576040517f5b08ba1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161082a565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260058401602090815260408083209488168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b73ffffffffffffffffffffffffffffffffffffffff83163b15610c22576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063150b7a029061270190339088908790879060040161380d565b6020604051808303816000875af192505050801561275a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261275791810190613a32565b60015b6127e9573d808015612788576040519150601f19603f3d011682016040523d82523d6000602084013e61278d565b606091505b5080516000036127e1576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161082a565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a02000000000000000000000000000000000000000000000000000000001461287c576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161082a565b5050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061291657507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061061557507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610615565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930081806129a8575073ffffffffffffffffffffffffffffffffffffffff831615155b15612b1c5760006129b885611b7a565b905073ffffffffffffffffffffffffffffffffffffffff841615801590612a0b57508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015612a69575073ffffffffffffffffffffffffffffffffffffffff80821660009081527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079305602090815260408083209388168352929052205460ff16155b15612ab8576040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161082a565b8215612b1a57848673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b600093845260040160205250506040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff8216612bc2576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b6000612bd0838360006122af565b905073ffffffffffffffffffffffffffffffffffffffff811615610fe3576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081526000600482015260240161082a565b6000600154826000015183604001518460200151612c4191906136e2565b612c4b91906137be565b6106159190613783565b612c5d613083565b61073182826130ea565b612c6f613083565b612c7761312d565b565b60008281527f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab007930260205260408120547f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793009073ffffffffffffffffffffffffffffffffffffffff90811690841615612cf457612cf4818587613135565b73ffffffffffffffffffffffffffffffffffffffff811615612d6c57612d1e600086600080612966565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600383016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555b73ffffffffffffffffffffffffffffffffffffffff861615612db75773ffffffffffffffffffffffffffffffffffffffff861660009081526003830160205260409020805460010190555b600085815260028301602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a811691821790925591518893918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a495945050505050565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed006000612e6a846111a1565b6000848152600184016020526040902054909150808214612ecc5773ffffffffffffffffffffffffffffffffffffffff851660009081526020848152604080832085845282528083205484845281842081905583526001860190915290208190555b506000928352600182016020908152604080852085905573ffffffffffffffffffffffffffffffffffffffff9095168452918252838320908352905290812055565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed02547f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0090600090612f61906001906136e2565b6000848152600384016020526040812054600285018054939450909284908110612f8d57612f8d613741565b9060005260206000200154905080846002018381548110612fb057612fb0613741565b600091825260208083209091019290925582815260038601909152604080822084905586825281205560028401805480612fec57612fec613a4f565b600190038181906000526020600020016000905590555050505050565b7f645e039705490088daad89bae25049a34f4a9072d398537b1ab2425f24cbed0060006001613037856111a1565b61304191906136e2565b73ffffffffffffffffffffffffffffffffffffffff90941660009081526020838152604080832087845282528083208690559482526001909301909252502055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16612c77576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130f2613083565b7f80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab00793008061311e8482613918565b5060018101610c228382613918565b611f3e613083565b613140838383612408565b610fe35773ffffffffffffffffffffffffffffffffffffffff8316613194576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810182905260240161082a565b6040517f177e802f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024810182905260440161082a565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610f0c57600080fd5b60006020828403121561322557600080fd5b8135611b1d816131e5565b6000815180845260005b818110156132565760208185018101518683018201520161323a565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611b1d6020830184613230565b6000602082840312156132b957600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146132e457600080fd5b919050565b600080604083850312156132fc57600080fd5b613305836132c0565b946020939093013593505050565b8015158114610f0c57600080fd5b6000806000806080858703121561333757600080fd5b843593506020850135925061334e604086016132c0565b9150606085013561335e81613313565b939692955090935050565b6000806040838503121561337c57600080fd5b50508035926020909101359150565b6000806000606084860312156133a057600080fd5b6133a9846132c0565b92506133b7602085016132c0565b91506133c5604085016132c0565b90509250925092565b6000806000606084860312156133e357600080fd5b6133ec846132c0565b92506133fa602085016132c0565b9150604084013590509250925092565b60006020828403121561341c57600080fd5b611b1d826132c0565b6000806020838503121561343857600080fd5b823567ffffffffffffffff8082111561345057600080fd5b818501915085601f83011261346457600080fd5b81358181111561347357600080fd5b8660208260051b850101111561348857600080fd5b60209290920196919550909350505050565b600080604083850312156134ad57600080fd5b6134b6836132c0565b915060208301356134c681613313565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000806080858703121561351657600080fd5b61351f856132c0565b935061352d602086016132c0565b925060408501359150606085013567ffffffffffffffff8082111561355157600080fd5b818701915087601f83011261356557600080fd5b813581811115613577576135776134d1565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135bd576135bd6134d1565b816040528281528a60208487010111156135d657600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060006060848603121561360f57600080fd5b8335925060208401359150604084013561362881613313565b809150509250925092565b6000806040838503121561364657600080fd5b61364f836132c0565b915061365d602084016132c0565b90509250929050565b600181811c9082168061367a57607f821691505b602082108103611886577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610615576106156136b3565b60006020828403121561370757600080fd5b8151611b1d81613313565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80820180821115610615576106156136b3565b6000826137b9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8082028115828204841417610615576106156136b3565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613806576138066136b3565b5060010190565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152611f346080830184613230565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8481526020810184905260808101600584106138c0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60408201939093526060015292915050565b601f821115610fe357600081815260208120601f850160051c810160208610156138f95750805b601f850160051c820191505b81811015611ad457828155600101613905565b815167ffffffffffffffff811115613932576139326134d1565b613946816139408454613666565b846138d2565b602080601f83116001811461399957600084156139635750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611ad4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156139e6578886015182559484019460019091019084016139c7565b5085821015613a2257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613a4457600080fd5b8151611b1d816131e5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220f2be9ef63c8cff84424c4cc6ce88dc4fafa26cc588aa7e368cdf7698ca087d6564736f6c63430008140033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.