ETH Price: $1,914.03 (-3.19%)
 

Overview

Max Total Supply

3,183,346,505,441,686.2693 Test

Holders

2

Transfers

-
-

Market

Onchain Market Cap

-

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
LiquidityManager

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 100 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC4626Partial} from "../IERC4626Partial.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

contract LiquidityManager is ERC20, Ownable, ReentrancyGuard {
    using EnumerableSet for EnumerableSet.Bytes32Set;
    uint256 public allocatedAssets;
    uint256 public totalAssets;

    struct Vault {
        uint8 weight;
        address vault;
    }

    EnumerableSet.Bytes32Set private _vaults;
    uint256 public totalWeight;
    address private immutable _self;

    constructor() 
        ERC20("Test", "Test")
        Ownable(msg.sender) {
        _self = address(this);
    }

    function getVaultCount() external view returns (uint256) {
        return _vaults.length();
    }

    function getVaultAt(uint256 index) external view returns (Vault memory) {
        require(index < _vaults.length(), "Index out of bounds");
        return _bytes32ToVault(_vaults.at(index));
    }

    // Helper function to convert Vault struct to bytes32
    function _vaultToBytes32(Vault memory vault) internal pure returns (bytes32) {
        return bytes32((uint256(uint8(vault.weight)) << 160) | uint160(vault.vault));
    }

    // Helper function to convert bytes32 to Vault struct
    function _bytes32ToVault(bytes32 data) internal pure returns (Vault memory) {
        uint8 weight = uint8(uint256(data) >> 160);
        address vault = address(uint160(uint256(data)));
        return Vault(weight, vault);
    }

    function addVault(address vault, uint8 weight) external onlyOwner {
        Vault memory newVault = Vault(weight, vault);
        require(_vaults.add(_vaultToBytes32(newVault)), "addVault: Vault already exists");
        totalWeight += weight;

        emit VaultAdded(vault);
    }

    function removeVault(uint256 index) external onlyOwner {
        Vault memory vaultToRemove = _bytes32ToVault(_vaults.at(index));
        require(_vaults.remove(_vaultToBytes32(vaultToRemove)), "removeVault: Vault does not exist");

        totalWeight -= vaultToRemove.weight;
        uint256 assets = IERC4626Partial(vaultToRemove.vault).totalAssets();

        if (assets > 0) {
            IERC4626Partial(vaultToRemove.vault).withdraw(assets, _self, _self);
            totalAssets -= assets;
        }

        emit VaultRemoved(vaultToRemove.vault);
    }

    function stake() external payable nonReentrant {
        require(msg.value > 0, "stake: Invalid amount");
        require(totalWeight > 0, "stake: Total weight is 0");
        
        uint256 amount = msg.value;
        uint256 count = _vaults.length();

        for (uint i = 0; i < count; i++) {
            Vault memory v = _bytes32ToVault(_vaults.at(i));
            uint256 portion = (amount * v.weight) / totalWeight;

            IERC4626Partial vault = IERC4626Partial(v.vault);
            address asset = vault.asset();
            uint256 valueBefore = vault.getValueInEth(asset);
            vault.deposit{value: portion}(portion, _self);
            uint256 valueAfter = vault.getValueInEth(asset);
            
            uint256 assets = vault.totalAssets();
            if (assets > 0 && valueAfter > valueBefore) {
                // Use a scale factor of 1e18 for precision
                uint256 SCALE = 1e18;

                uint256 delta = valueAfter - valueBefore;
                
                // Calculate ratio with scaling
                uint256 scaledRatio = (delta * SCALE) / assets;
                
                // Calculate shares maintaining precision
                uint256 shares = (scaledRatio * portion) / SCALE;
                
                // Ensure minimum share amount
                shares = shares > 0 ? shares : portion;
                
                _mint(msg.sender, shares);
            } else {
                // If no assets yet, use 1:1 ratio
                _mint(msg.sender, portion);
            }
        }

        totalAssets += amount;
        emit Staked(msg.sender, msg.value);
    }

    function unstake(uint256 shares) external nonReentrant {
        require(shares > 0, "unstake: Invalid amount");
        require(totalWeight > 0, "unstake: Total weight is 0");
        require(balanceOf(msg.sender) >= shares, "unstake: Insufficient balance");
        
        _burn(msg.sender, shares);
        
        uint256 assets = 0;
        uint256 count = _vaults.length();
        uint256 SCALE = 1e18;
        
        for (uint i = 0; i < count; i++) {
            Vault memory v = _bytes32ToVault(_vaults.at(i));
            
            // Calculate portion with scaling to prevent precision loss
            uint256 portion = (shares * v.weight * SCALE) / totalWeight;
            
            IERC4626Partial vault = IERC4626Partial(v.vault);
            uint256 assetsBefore = _self.balance;
            
            // Withdraw scaled portion
            vault.withdraw(portion / SCALE, _self, _self);
            
            uint256 assetsAfter = _self.balance;
            assets += assetsAfter - assetsBefore;
        }
        
        totalAssets -= assets;
        payable(msg.sender).transfer(assets);
        
        emit Unstaked(msg.sender, assets);
    }

    event Staked(address indexed account, uint256 amount);
    event Unstaked(address indexed account, uint256 amount);
    event VaultAdded(address indexed vault);
    event VaultRemoved(address indexed vault);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC-20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 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 ERC-721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-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 ERC-1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 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.1.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC-20
 * applications.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Skips emitting an {Approval} event indicating an allowance update. This is not
     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     *
     * ```solidity
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import { IOracle } from "./IOracle.sol";

interface IERC4626Partial is IOracle {
    function asset() external view returns (address);
    function deposit(uint256 assets, address receiver) external payable returns (uint256 shares);
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
    function totalAssets() external view returns (uint256);

    event Deposit(address indexed sender, address indexed owner, uint256 assets);
    event Withdraw(address indexed sender, uint256 assets);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

interface IOracle {
    function getValueInEth(address token) external returns (uint256);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "viaIR": true,
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"VaultAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"VaultRemoved","type":"event"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint8","name":"weight","type":"uint8"}],"name":"addVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allocatedAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getVaultAt","outputs":[{"components":[{"internalType":"uint8","name":"weight","type":"uint8"},{"internalType":"address","name":"vault","type":"address"}],"internalType":"struct LiquidityManager.Vault","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a0604052346103595761001161035e565b61001961035e565b81516001600160401b03811161026457600354600181811c9116801561034f575b602082101461024457601f81116102ea575b50602092601f8211600114610285579281929360009261027a575b50508160011b916000199060031b1c1916176003555b80516001600160401b03811161026457600454600181811c9116801561025a575b602082101461024457601f81116101df575b50602091601f821160011461017b57918192600092610170575b50508160011b916000199060031b1c1916176004555b331561015a5760058054336001600160a01b03198216811790925560405191906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3600160065530608052611616908161038f8239608051818181610298015281816107e70152610c870152f35b631e4fbdf760e01b600052600060045260246000fd5b0151905038806100ca565b601f198216926004600052806000209160005b8581106101c7575083600195106101ae575b505050811b016004556100e0565b015160001960f88460031b161c191690553880806101a0565b9192602060018192868501518155019401920161018e565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c8101916020841061023a575b601f0160051c01905b81811061022e57506100b0565b60008155600101610221565b9091508190610218565b634e487b7160e01b600052602260045260246000fd5b90607f169061009e565b634e487b7160e01b600052604160045260246000fd5b015190503880610067565b601f198216936003600052806000209160005b8681106102d257508360019596106102b9575b505050811b0160035561007d565b015160001960f88460031b161c191690553880806102ab565b91926020600181928685015181550194019201610298565b60036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c81019160208410610345575b601f0160051c01905b818110610339575061004c565b6000815560010161032c565b9091508190610323565b90607f169061003a565b600080fd5b60408051919082016001600160401b0381118382101761026457604052600482526315195cdd60e21b602083015256fe608080604052600436101561001357600080fd5b60003560e01c90816301e1d114146111855750806306fdde03146110c7578063095ea7b31461104157806318160ddd1461102357806323b872dd14610f365780632e17de7814610bf1578063313ce56714610bd557806336cd2b1114610bb75780633a4b66f1146107bd57806370a0823114610783578063715018a61461072657806374d4e491146107085780637a98742d146106775780637a9b27d01461058c5780638da5cb5b1461056357806395d89b411461045c57806396c82e571461043e578063a9059cbb1461040d578063dd62ed3e146103bc578063eaadd976146101955763f2fde38b1461010657600080fd5b346101905760203660031901126101905761011f6111e9565b61012761140b565b6001600160a01b0316801561017a57600580546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b34610190576020366003190112610190576101ae61140b565b6101c86101bc600435611434565b90549060031b1c61138e565b805160208201516101f09160ff60a01b60a09190911b166001600160a01b03909116176114ef565b1561036d578061020860ff6020935116600b5461129c565b600b550180516040516278744560e21b815290602090829060049082906001600160a01b03165afa90811561032c57600091610338575b5080610278575b50516001600160a01b03167fe71f3a50e5ad81964f352c411f1d45e35438ecd1acecef59ac81d9fbbf6cbc0a600080a2005b8151604051632d182be560e21b8152600481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301819052604483015290929160209184916064918391600091165af1801561032c576102f9575b6102f0915060085461129c565b60085581610246565b6020823d602011610324575b8161031260209383611247565b81010312610190576102f091506102e3565b3d9150610305565b6040513d6000823e3d90fd5b906020823d602011610365575b8161035260209383611247565b810103126103625750518261023f565b80fd5b3d9150610345565b60405162461bcd60e51b815260206004820152602160248201527f72656d6f76655661756c743a205661756c7420646f6573206e6f7420657869736044820152601d60fa1b6064820152608490fd5b34610190576040366003190112610190576103d56111e9565b6103dd6111ff565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b34610190576040366003190112610190576104336104296111e9565b60243590336112cf565b602060405160018152f35b34610190576000366003190112610190576020600b54604051908152f35b346101905760003660031901126101905760405160006004548060011c90600181168015610559575b6020831081146105455782855290811561052157506001146104c2575b6104be836104b281850382611247565b604051918291826111a0565b0390f35b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b808210610507575090915081016020016104b26104a2565b9192600181602092548385880101520191019092916104ef565b60ff191660208086019190915291151560051b840190910191506104b290506104a2565b634e487b7160e01b84526022600452602484fd5b91607f1691610485565b34610190576000366003190112610190576005546040516001600160a01b039091168152602090f35b34610190576040366003190112610190576105a56111e9565b60243560ff8116809103610190576105bb61140b565b6105f76105f2604051936105ce85611215565b8385526001600160a01b0316602090940184905260a083901b60ff60a01b16841790565b61147d565b156106325761060890600b546112a9565b600b557f7b7ef7a864d96a85497a1ed846adb39940dd6ccef678ff6ac8d55505e09b8cc4600080a2005b60405162461bcd60e51b815260206004820152601e60248201527f6164645661756c743a205661756c7420616c72656164792065786973747300006044820152606490fd5b34610190576020366003190112610190576004356106936112b6565b506009548110156106cd576106ac6101bc604092611434565b8151815160ff1681526020918201516001600160a01b031691810191909152f35b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606490fd5b34610190576000366003190112610190576020600954604051908152f35b346101905760003660031901126101905761073f61140b565b600580546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610190576020366003190112610190576001600160a01b036107a46111e9565b1660005260006020526020604060002054604051908152f35b6000366003190112610190576107d161136c565b3415610b7a57600b5415610b3a576009546000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316905b80831061085a57610824346008546112a9565b6008556040513481527f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d60203392a26001600655005b6108666101bc84611434565b9261088161087860ff86511634611269565b600b549061127c565b6020948501516040516338d52e0f60e01b81526001600160a01b039091169581600481895afa90811561032c57600091610af5575b506040516335827fa160e21b81526001600160a01b0390911660048201819052956020826024816000855af191821561032c57600092610ac2575b50604051636e553f6560e01b815283600482015286602482015260208160448187865af1801561032c57600090610a92575b5050604051966335827fa160e21b885260048801526020876024816000855af196871561032c57600097610a5e575b509560206004959697604051968780926278744560e21b82525afa94851561032c57600095610a2b575b5084151580610a22575b15610a0d57906109959161129c565b90670de0b6b3a7640000820291808304670de0b6b3a764000014901517156109f757670de0b6b3a76400006109d8826109d36001976109e89661127c565b611269565b049081156109f057505b336113bf565b019190610811565b90506109e2565b634e487b7160e01b600052601160045260246000fd5b505060019250610a1d90336113bf565b6109e8565b50818111610986565b90946020823d8211610a56575b81610a4560209383611247565b81010312610362575051938761097c565b3d9150610a38565b966020883d8211610a8a575b81610a7760209383611247565b8101031261036257509551956020610952565b3d9150610a6a565b6020823d8211610aba575b81610aaa60209383611247565b8101031261036257505188610923565b3d9150610a9d565b90916020823d8211610aed575b81610adc60209383611247565b8101031261036257505190876108f1565b3d9150610acf565b6020813d8211610b32575b81610b0d60209383611247565b81010312610b2e5751906001600160a01b03821682036103625750866108b6565b5080fd5b3d9150610b00565b60405162461bcd60e51b815260206004820152601860248201527707374616b653a20546f74616c2077656967687420697320360441b6044820152606490fd5b60405162461bcd60e51b81526020600482015260156024820152741cdd185ad94e88125b9d985b1a5908185b5bdd5b9d605a1b6044820152606490fd5b34610190576000366003190112610190576020600754604051908152f35b3461019057600036600319011261019057602060405160128152f35b3461019057602036600319011261019057600435610c0d61136c565b8015610ef757600b5415610eb2573360005260006020528060406000205410610e6d573315610e5757600033815280602052604081205491808310610e3e578083338452836020520360408320558060025403600255816040518281526000805160206115c183398151915260203392a3819060095483917f00000000000000000000000000000000000000000000000000000000000000005b828410610d22578585610cbc8160085461129c565b6008558180828015610d18575b8280929181923390f115610d0b576040519081527f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f7560203392a2600160065580f35b50604051903d90823e3d90fd5b6108fc9150610cc9565b90919293610d326101bc86611434565b610d4060ff82511685611269565b670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610e2a57602084610d728193600b549061127c565b93820151604051632d182be560e21b8152670de0b6b3a764000090950460048601526001600160a01b038281166024870152938416604486015290319392839160649183918d91165af18015610e1f57610de9575b50600191610dd9610ddf92853161129c565b906112a9565b9401929190610ca7565b916020833d8211610e17575b81610e0260209383611247565b81010312610e135791506001610dc7565b8780fd5b3d9150610df5565b6040513d8a823e3d90fd5b634e487b7160e01b88526011600452602488fd5b60649263391434e360e21b835233600452602452604452fd5b634b637e8f60e11b600052600060045260246000fd5b60405162461bcd60e51b815260206004820152601d60248201527f756e7374616b653a20496e73756666696369656e742062616c616e63650000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f756e7374616b653a20546f74616c2077656967687420697320300000000000006044820152606490fd5b60405162461bcd60e51b81526020600482015260176024820152761d5b9cdd185ad94e88125b9d985b1a5908185b5bdd5b9d604a1b6044820152606490fd5b3461019057606036600319011261019057610f4f6111e9565b610f576111ff565b6001600160a01b0382166000818152600160208181526040808420338552909152909120549193604435939290918101610f97575b5061043393506112cf565b838110611006578415610ff0573315610fda57610433946000526001602052604060002060018060a01b0333166000526020528360406000209103905584610f8c565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8390637dc7a0d960e11b6000523360045260245260445260646000fd5b34610190576000366003190112610190576020600254604051908152f35b346101905760403660031901126101905761105a6111e9565b602435903315610ff0576001600160a01b0316908115610fda57336000526001602052604060002082600052602052806040600020556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346101905760003660031901126101905760405160006003548060011c9060018116801561117b575b60208310811461054557828552908115610521575060011461111c576104be836104b281850382611247565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b808210611161575090915081016020016104b26104a2565b919260018160209254838588010152019101909291611149565b91607f16916110f0565b34610190576000366003190112610190576020906008548152f35b91909160208152825180602083015260005b8181106111d3575060409293506000838284010152601f8019910116010190565b80602080928701015160408286010152016111b2565b600435906001600160a01b038216820361019057565b602435906001600160a01b038216820361019057565b6040810190811067ffffffffffffffff82111761123157604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761123157604052565b818102929181159184041417156109f757565b8115611286570490565b634e487b7160e01b600052601260045260246000fd5b919082039182116109f757565b919082018092116109f757565b604051906112c382611215565b60006020838281520152565b6001600160a01b0316908115610e57576001600160a01b031691821561135657600082815280602052604081205482811061133c5791604082826000805160206115c1833981519152958760209652828652038282205586815280845220818154019055604051908152a3565b916064928463391434e360e21b8452600452602452604452fd5b63ec442f0560e01b600052600060045260246000fd5b60026006541461137d576002600655565b633ee5aeb560e01b60005260046000fd5b6113966112b6565b50604051906113a482611215565b60a081901c60ff1682526001600160a01b0316602082015290565b6001600160a01b0316908115611356576113db816002546112a9565b6002556000805160206115c1833981519152602060009284845283825260408420818154019055604051908152a3565b6005546001600160a01b0316330361141f57565b63118cdaa760e01b6000523360045260246000fd5b60095481101561144f57600960005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b805482101561144f5760005260206000200190600090565b80600052600a602052604060002054156000146114e957600954600160401b811015611231576114d06114b98260018594016009556009611465565b819391549060031b91821b91600019901b19161790565b905560095490600052600a602052604060002055600190565b50600090565b6000818152600a602052604090205480156115b95760001981018181116109f7576009546000198101919082116109f75781810361157f575b50505060095480156115695760001901611543816009611465565b8154906000199060031b1b19169055600955600052600a60205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b6115a16115906114b9936009611465565b90549060031b1c9283926009611465565b9055600052600a602052604060002055388080611528565b505060009056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212206436e5ed6d22c61a60fc0199f2ea6e28cc108d50b93909cf15c7231b8de372a164736f6c634300081b0033

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c90816301e1d114146111855750806306fdde03146110c7578063095ea7b31461104157806318160ddd1461102357806323b872dd14610f365780632e17de7814610bf1578063313ce56714610bd557806336cd2b1114610bb75780633a4b66f1146107bd57806370a0823114610783578063715018a61461072657806374d4e491146107085780637a98742d146106775780637a9b27d01461058c5780638da5cb5b1461056357806395d89b411461045c57806396c82e571461043e578063a9059cbb1461040d578063dd62ed3e146103bc578063eaadd976146101955763f2fde38b1461010657600080fd5b346101905760203660031901126101905761011f6111e9565b61012761140b565b6001600160a01b0316801561017a57600580546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b34610190576020366003190112610190576101ae61140b565b6101c86101bc600435611434565b90549060031b1c61138e565b805160208201516101f09160ff60a01b60a09190911b166001600160a01b03909116176114ef565b1561036d578061020860ff6020935116600b5461129c565b600b550180516040516278744560e21b815290602090829060049082906001600160a01b03165afa90811561032c57600091610338575b5080610278575b50516001600160a01b03167fe71f3a50e5ad81964f352c411f1d45e35438ecd1acecef59ac81d9fbbf6cbc0a600080a2005b8151604051632d182be560e21b8152600481018390526001600160a01b037f00000000000000000000000008156a3ce454dfc8a8a8dc96360f9cf30b69fd3e811660248301819052604483015290929160209184916064918391600091165af1801561032c576102f9575b6102f0915060085461129c565b60085581610246565b6020823d602011610324575b8161031260209383611247565b81010312610190576102f091506102e3565b3d9150610305565b6040513d6000823e3d90fd5b906020823d602011610365575b8161035260209383611247565b810103126103625750518261023f565b80fd5b3d9150610345565b60405162461bcd60e51b815260206004820152602160248201527f72656d6f76655661756c743a205661756c7420646f6573206e6f7420657869736044820152601d60fa1b6064820152608490fd5b34610190576040366003190112610190576103d56111e9565b6103dd6111ff565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b34610190576040366003190112610190576104336104296111e9565b60243590336112cf565b602060405160018152f35b34610190576000366003190112610190576020600b54604051908152f35b346101905760003660031901126101905760405160006004548060011c90600181168015610559575b6020831081146105455782855290811561052157506001146104c2575b6104be836104b281850382611247565b604051918291826111a0565b0390f35b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b808210610507575090915081016020016104b26104a2565b9192600181602092548385880101520191019092916104ef565b60ff191660208086019190915291151560051b840190910191506104b290506104a2565b634e487b7160e01b84526022600452602484fd5b91607f1691610485565b34610190576000366003190112610190576005546040516001600160a01b039091168152602090f35b34610190576040366003190112610190576105a56111e9565b60243560ff8116809103610190576105bb61140b565b6105f76105f2604051936105ce85611215565b8385526001600160a01b0316602090940184905260a083901b60ff60a01b16841790565b61147d565b156106325761060890600b546112a9565b600b557f7b7ef7a864d96a85497a1ed846adb39940dd6ccef678ff6ac8d55505e09b8cc4600080a2005b60405162461bcd60e51b815260206004820152601e60248201527f6164645661756c743a205661756c7420616c72656164792065786973747300006044820152606490fd5b34610190576020366003190112610190576004356106936112b6565b506009548110156106cd576106ac6101bc604092611434565b8151815160ff1681526020918201516001600160a01b031691810191909152f35b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606490fd5b34610190576000366003190112610190576020600954604051908152f35b346101905760003660031901126101905761073f61140b565b600580546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610190576020366003190112610190576001600160a01b036107a46111e9565b1660005260006020526020604060002054604051908152f35b6000366003190112610190576107d161136c565b3415610b7a57600b5415610b3a576009546000907f00000000000000000000000008156a3ce454dfc8a8a8dc96360f9cf30b69fd3e6001600160a01b0316905b80831061085a57610824346008546112a9565b6008556040513481527f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d60203392a26001600655005b6108666101bc84611434565b9261088161087860ff86511634611269565b600b549061127c565b6020948501516040516338d52e0f60e01b81526001600160a01b039091169581600481895afa90811561032c57600091610af5575b506040516335827fa160e21b81526001600160a01b0390911660048201819052956020826024816000855af191821561032c57600092610ac2575b50604051636e553f6560e01b815283600482015286602482015260208160448187865af1801561032c57600090610a92575b5050604051966335827fa160e21b885260048801526020876024816000855af196871561032c57600097610a5e575b509560206004959697604051968780926278744560e21b82525afa94851561032c57600095610a2b575b5084151580610a22575b15610a0d57906109959161129c565b90670de0b6b3a7640000820291808304670de0b6b3a764000014901517156109f757670de0b6b3a76400006109d8826109d36001976109e89661127c565b611269565b049081156109f057505b336113bf565b019190610811565b90506109e2565b634e487b7160e01b600052601160045260246000fd5b505060019250610a1d90336113bf565b6109e8565b50818111610986565b90946020823d8211610a56575b81610a4560209383611247565b81010312610362575051938761097c565b3d9150610a38565b966020883d8211610a8a575b81610a7760209383611247565b8101031261036257509551956020610952565b3d9150610a6a565b6020823d8211610aba575b81610aaa60209383611247565b8101031261036257505188610923565b3d9150610a9d565b90916020823d8211610aed575b81610adc60209383611247565b8101031261036257505190876108f1565b3d9150610acf565b6020813d8211610b32575b81610b0d60209383611247565b81010312610b2e5751906001600160a01b03821682036103625750866108b6565b5080fd5b3d9150610b00565b60405162461bcd60e51b815260206004820152601860248201527707374616b653a20546f74616c2077656967687420697320360441b6044820152606490fd5b60405162461bcd60e51b81526020600482015260156024820152741cdd185ad94e88125b9d985b1a5908185b5bdd5b9d605a1b6044820152606490fd5b34610190576000366003190112610190576020600754604051908152f35b3461019057600036600319011261019057602060405160128152f35b3461019057602036600319011261019057600435610c0d61136c565b8015610ef757600b5415610eb2573360005260006020528060406000205410610e6d573315610e5757600033815280602052604081205491808310610e3e578083338452836020520360408320558060025403600255816040518281526000805160206115c183398151915260203392a3819060095483917f00000000000000000000000008156a3ce454dfc8a8a8dc96360f9cf30b69fd3e5b828410610d22578585610cbc8160085461129c565b6008558180828015610d18575b8280929181923390f115610d0b576040519081527f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f7560203392a2600160065580f35b50604051903d90823e3d90fd5b6108fc9150610cc9565b90919293610d326101bc86611434565b610d4060ff82511685611269565b670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610e2a57602084610d728193600b549061127c565b93820151604051632d182be560e21b8152670de0b6b3a764000090950460048601526001600160a01b038281166024870152938416604486015290319392839160649183918d91165af18015610e1f57610de9575b50600191610dd9610ddf92853161129c565b906112a9565b9401929190610ca7565b916020833d8211610e17575b81610e0260209383611247565b81010312610e135791506001610dc7565b8780fd5b3d9150610df5565b6040513d8a823e3d90fd5b634e487b7160e01b88526011600452602488fd5b60649263391434e360e21b835233600452602452604452fd5b634b637e8f60e11b600052600060045260246000fd5b60405162461bcd60e51b815260206004820152601d60248201527f756e7374616b653a20496e73756666696369656e742062616c616e63650000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f756e7374616b653a20546f74616c2077656967687420697320300000000000006044820152606490fd5b60405162461bcd60e51b81526020600482015260176024820152761d5b9cdd185ad94e88125b9d985b1a5908185b5bdd5b9d604a1b6044820152606490fd5b3461019057606036600319011261019057610f4f6111e9565b610f576111ff565b6001600160a01b0382166000818152600160208181526040808420338552909152909120549193604435939290918101610f97575b5061043393506112cf565b838110611006578415610ff0573315610fda57610433946000526001602052604060002060018060a01b0333166000526020528360406000209103905584610f8c565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8390637dc7a0d960e11b6000523360045260245260445260646000fd5b34610190576000366003190112610190576020600254604051908152f35b346101905760403660031901126101905761105a6111e9565b602435903315610ff0576001600160a01b0316908115610fda57336000526001602052604060002082600052602052806040600020556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346101905760003660031901126101905760405160006003548060011c9060018116801561117b575b60208310811461054557828552908115610521575060011461111c576104be836104b281850382611247565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b808210611161575090915081016020016104b26104a2565b919260018160209254838588010152019101909291611149565b91607f16916110f0565b34610190576000366003190112610190576020906008548152f35b91909160208152825180602083015260005b8181106111d3575060409293506000838284010152601f8019910116010190565b80602080928701015160408286010152016111b2565b600435906001600160a01b038216820361019057565b602435906001600160a01b038216820361019057565b6040810190811067ffffffffffffffff82111761123157604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761123157604052565b818102929181159184041417156109f757565b8115611286570490565b634e487b7160e01b600052601260045260246000fd5b919082039182116109f757565b919082018092116109f757565b604051906112c382611215565b60006020838281520152565b6001600160a01b0316908115610e57576001600160a01b031691821561135657600082815280602052604081205482811061133c5791604082826000805160206115c1833981519152958760209652828652038282205586815280845220818154019055604051908152a3565b916064928463391434e360e21b8452600452602452604452fd5b63ec442f0560e01b600052600060045260246000fd5b60026006541461137d576002600655565b633ee5aeb560e01b60005260046000fd5b6113966112b6565b50604051906113a482611215565b60a081901c60ff1682526001600160a01b0316602082015290565b6001600160a01b0316908115611356576113db816002546112a9565b6002556000805160206115c1833981519152602060009284845283825260408420818154019055604051908152a3565b6005546001600160a01b0316330361141f57565b63118cdaa760e01b6000523360045260246000fd5b60095481101561144f57600960005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b805482101561144f5760005260206000200190600090565b80600052600a602052604060002054156000146114e957600954600160401b811015611231576114d06114b98260018594016009556009611465565b819391549060031b91821b91600019901b19161790565b905560095490600052600a602052604060002055600190565b50600090565b6000818152600a602052604090205480156115b95760001981018181116109f7576009546000198101919082116109f75781810361157f575b50505060095480156115695760001901611543816009611465565b8154906000199060031b1b19169055600955600052600a60205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b6115a16115906114b9936009611465565b90549060031b1c9283926009611465565b9055600052600a602052604060002055388080611528565b505060009056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212206436e5ed6d22c61a60fc0199f2ea6e28cc108d50b93909cf15c7231b8de372a164736f6c634300081b0033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.