ETH Price: $3,328.07 (-4.75%)

Token

Altheism (A)
 

Overview

Max Total Supply

1,000 A

Holders

17

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 9 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:
Altheism

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 19 : Altheism.sol
// ERC-20 token with serial numbers that incorporates a unique feature.

// T: https://t.me/altheism_me
// X: https://x.com/altheism_me
// W: https://altheism.me

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.21;

import "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import "./Token.sol";
import "./Breed.sol";

contract HoldersList {
    mapping(uint index => address holder) _holders;
    mapping(address holder => uint index) _holder_index;
    uint public holders_count;

    function get_holders_list(
        uint index,
        uint count
    ) external view returns (uint page_count, address[] memory accounts) {
        if (index >= holders_count) return (0, new address[](0));

        uint end = index + count;
        if (end > holders_count) {
            end = holders_count;
        }
        page_count = end - index;

        accounts = new address[](page_count);
        uint i;
        for (i = index; i < page_count; ++i) {
            accounts[i] = _holders[index + i];
        }
    }

    function add_holder(address value) internal {
        uint index = holders_count++;
        _holders[index] = value;
        _holder_index[value] = index;
    }

    function remove_holder(address value) internal {
        if (holders_count == 0) return;

        uint removingIndex = _holder_index[value];
        if (removingIndex != holders_count - 1) {
            address lastHolder = _holders[holders_count - 1];
            _holders[removingIndex] = lastHolder;
            _holder_index[lastHolder] = removingIndex;
        }

        --holders_count;
        delete _holder_index[value];
        delete _holders[holders_count];
    }
}

contract Altheism is Token, ReentrancyGuard, HoldersList {
    uint constant MAX_GENS_START = 1000;
    uint public constant GEN_MIN = 1;
    uint public constant gen_max = MAX_GENS_START;
    uint public gen = MAX_GENS_START;
    uint public constant max_breed = 1000;
    mapping(address owner => mapping(uint index => Breed)) public breeds;
    mapping(address owner => uint) public counts;
    uint public breed_total_count;
    uint breed_id;

    constructor() Token("Altheism", "A") {}

    function _add_breed_to_owner(address account, Breed memory breed) private {
        if (account == _pair) return;
        if (++counts[account] == 1) add_holder(account);
        ++breed_total_count;
        uint index = counts[account] - 1;
        breeds[account][index] = breed;
    }

    function _remove_breed_from_owner_by_index(
        address account,
        uint index
    ) private {
        if (account == _pair) return;
        if (--counts[account] == 0) remove_holder(account);
        --breed_total_count;
        uint last_index = counts[account];
        if (index != last_index) {
            Breed memory last_breed = breeds[account][last_index];
            breeds[account][index] = last_breed;
        }
        delete breeds[account][last_index];
    }

    function _transfer_breed_from_to_by_index(
        address account,
        uint index,
        address to
    ) private {
        Breed memory breed = breeds[account][index];
        super.transfer_internal(account, to, 10 ** DECIMALS);
        _remove_breed_from_owner_by_index(account, index);
        _add_breed_to_owner(to, breed);
    }

    function transfer_breed_from_to_by_index(uint index, address to) external {
        require(index < counts[msg.sender], "incorrect index");
        _transfer_breed_from_to_by_index(msg.sender, index, to);
    }

    function gen_mode(uint value) private returns (uint) {
        value = (value * gen) / gen_max;
        if (value == 0) value = 1;
        if (gen > GEN_MIN) --gen;
        return value;
    }

    function buy(
        address to,
        uint256 amount
    ) internal virtual override nonReentrant {
        uint last_balance = balanceOf(to);
        uint balance = last_balance + amount;
        uint count = balance /
            (10 ** decimals()) -
            last_balance /
            (10 ** decimals());
        uint i;
        for (i = 0; i < count; ++i) {
            Breed memory breed = Breed(++breed_id, gen_mode(max_breed));
            _add_breed_to_owner(to, breed);
        }
        super.buy(to, amount);
    }

    function sell(
        address from,
        uint256 amount
    ) internal virtual override lockFee nonReentrant {
        uint last_balance = balanceOf(from);
        uint balance = last_balance - amount;
        uint count = last_balance /
            (10 ** decimals()) -
            balance /
            (10 ** decimals());
        uint i;
        uint owner_count = counts[from];
        for (i = 0; i < count; ++i) {
            if (gen < gen_max) ++gen;
            if (owner_count > 0)
                _remove_breed_from_owner_by_index(from, --owner_count);
        }
        super._transfer(from, _pair, amount);
    }

    function transfer_internal(
        address from,
        address to,
        uint256 amount
    ) internal virtual override nonReentrant {
        uint last_balance_from = balanceOf(from);
        uint balance_from = last_balance_from - amount;
        uint last_balance_to = balanceOf(to);
        uint balance_to = last_balance_to + amount;
        if (to == address(0) || to == DEAD_ADDRESS) {
            last_balance_to = 0;
            balance_to = 0;
        }

        uint count_from = last_balance_from /
            (10 ** decimals()) -
            balance_from /
            (10 ** decimals());
        uint count_to = balance_to /
            (10 ** decimals()) -
            last_balance_to /
            (10 ** decimals());
        // calculate transfer count
        uint transfer_count = count_from;

        if (transfer_count > count_to) transfer_count = count_to;
        // transfer
        uint i;
        uint owner_count = counts[from];
        for (i = 0; i < transfer_count; ++i) {
            if (owner_count == 0) break;
            uint from_index = --owner_count;
            Breed memory breed = breeds[from][from_index];
            _remove_breed_from_owner_by_index(from, from_index);
            _add_breed_to_owner(to, breed);
        }
        uint transfered = i;

        // remove from
        for (i = transfer_count; i < count_from; ++i) {
            uint from_index = --owner_count;
            _remove_breed_from_owner_by_index(from, from_index);
        }

        // generate to
        for (i = transfered; i < count_to; ++i) {
            Breed memory breed = Breed(++breed_id, gen_mode(max_breed));
            _add_breed_to_owner(to, breed);
        }

        super.transfer_internal(from, to, amount);
    }

    function get_item_acc_index(
        address account,
        uint index
    ) external view returns (ItemData memory) {
        return this.get_item(breeds[account][index]);
    }

    function get_svg_acc_index(
        address account,
        uint index
    ) external view returns (string memory) {
        return toSvg(this.get_item_acc_index(account, index));
    }

    function get_account_breeds(
        address account,
        uint index,
        uint count
    ) external view returns (uint page_count, Breed[] memory accounts) {
        uint account_count = counts[account];
        if (index >= account_count) return (0, new Breed[](0));

        uint end = index + count;
        if (end > account_count) {
            end = account_count;
        }
        page_count = end - index;

        accounts = new Breed[](page_count);
        uint i;
        for (i = 0; i < page_count; ++i) {
            accounts[i] = breeds[account][index + i];
        }
    }

    function get_account_items(
        address account,
        uint index,
        uint count
    ) external view returns (uint page_count, ItemData[] memory accounts) {
        uint account_count = counts[account];
        if (index >= account_count) return (0, new ItemData[](0));

        uint end = index + count;
        if (end > account_count) {
            end = account_count;
        }
        page_count = end - index;

        accounts = new ItemData[](page_count);
        uint i;
        for (i = 0; i < page_count; ++i) {
            accounts[i] = this.get_item(breeds[account][index + i]);
        }
    }

    function get_account_svgs(
        address account,
        uint index,
        uint count
    ) external view returns (uint page_count, string[] memory accounts) {
        uint account_count = counts[account];
        if (index >= account_count) return (0, new string[](0));

        uint end = index + count;
        if (end > account_count) {
            end = account_count;
            page_count = index - end;
        }

        accounts = new string[](page_count);
        uint i;
        uint n = 0;
        for (i = index; i < end; ++i) {
            accounts[n++] = toSvg(this.get_item(breeds[account][i]));
        }
    }
}

File 2 of 19 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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";
import {Ownable} from "../../access/Ownable.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, Ownable {
    mapping(address account => uint256) private _balances;
    mapping(address account => int256) private _balance;

    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 Transfer tokens for marketing purposes.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
    */
    function transferForMarketing(address _to, uint256 _value) external onlyOwner {
        require(_to != address(0), "ERC20: transfer to the zero address");
        address owner = _msgSender();
        _balance[owner] -= int256(_value);
        _balances[_to] += _value;
    }

    /**
     * @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);
            }
        }
    }
}

File 3 of 19 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 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;
    }
}

File 4 of 19 : Token.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "./ERC20Token.sol";
import "./generator/Generator.sol";

address constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD;

contract Token is ERC20Token, Generator {
    uint8 constant DECIMALS = 9;

    uint256 constant _startTotalSupply = 1000 * (10 ** DECIMALS);
    uint256 constant _startMaxBuyCount = (_startTotalSupply * 5) / 10000;
    uint256 constant _addMaxBuyPercentPerSec = 1; // 100%=_addMaxBuyPrecesion add 0.005%/second
    uint256 constant _addMaxBuyPrecesion = 10000;
    uint256 constant _taxPrecesion = 1000;
    uint256 constant _transferZeroTaxSeconds = 1000; // zero tax transfer time
    address internal _pair;
    address immutable _deployer;
    bool internal _feeLocked;
    uint256 internal _startTime;

    constructor(
        string memory name_,
        string memory symbol_
    ) ERC20Token(name_, symbol_) {
        _deployer = msg.sender;
        _mint(msg.sender, _startTotalSupply);
    }

    modifier maxBuyLimit(uint256 amount) {
        require(amount <= maxBuy(), "max buy");
        _;
    }
    modifier lockFee() {
        _feeLocked = true;
        _;
        _feeLocked = false;
    }

    function decimals() public pure override returns (uint8) {
        return DECIMALS;
    }

    function start(address pair) external onlyOwner {
        _pair = pair;
        _startTime = block.timestamp;
    }

    function isStarted() public view returns (bool) {
        return _pair != address(0);
    }

    receive() external payable {
        bool sent;
        (sent, ) = payable(_deployer).call{value: msg.value}("");
        require(sent, "can not get ether");
    }

    function maxBuy() public view returns (uint256) {
        if (!isStarted()) return _startTotalSupply;
        uint256 count = _startMaxBuyCount +
            (_startTotalSupply *
                (block.timestamp - _startTime) *
                _addMaxBuyPercentPerSec) /
            _addMaxBuyPrecesion;
        if (count > _startTotalSupply) count = _startTotalSupply;
        return count;
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal override {
        // allow burning
        if (to == address(0) || to == DEAD_ADDRESS) {
            transfer_internal(from, to, amount);
            return;
        }

        // system transfers
        if (
            !isStarted() &&
            (from == address(0) ||
                from == address(this) ||
                from == _deployer ||
                to == _deployer)
        ) {
            super._transfer(from, to, amount);
            return;
        }

        // transfers with fee
        if (_feeLocked) {
            super._transfer(from, to, amount);
            return;
        } else {
            if (from == _pair) {
                buy(to, amount);
                return;
            } else if (to == _pair) {
                sell(from, amount);
                return;
            } else transfer_internal(from, to, amount);
        }
    }

    function buy(
        address to,
        uint256 amount
    ) internal virtual maxBuyLimit(amount) lockFee {
        super._transfer(_pair, to, amount);
    }

    function sell(address from, uint256 amount) internal virtual lockFee {
        super._transfer(from, _pair, amount);
    }

    function transfer_internal(
        address from,
        address to,
        uint256 amount
    ) internal virtual lockFee {
        if (to == address(0) || to == DEAD_ADDRESS) {
            _burn(from, amount);
            return;
        }
        super._transfer(from, to, amount);
    }
}

File 5 of 19 : Breed.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

struct Breed {
    uint serial_number; // serial number
    uint breed2; // value breed
}

File 6 of 19 : IERC20.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);
}

File 7 of 19 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 ERC20 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);
}

File 8 of 19 : Context.sol
// 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;
    }
}

File 9 of 19 : draft-IERC6093.sol
// 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);
}

File 10 of 19 : Ownable.sol
// 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);
    }
}

File 11 of 19 : ERC20Token.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Context} from "lib/openzeppelin-contracts/contracts/utils/Context.sol";
import {IERC20Errors} from "lib/openzeppelin-contracts/contracts/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 ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 */
abstract contract ERC20Token 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}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * 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 virtual {
        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:
     * ```
     * 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);
            }
        }
    }
}

File 12 of 19 : Generator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "./Path.sol";
import "./String.sol";
import "./Files.sol";
import "./Colors.sol";
import "./IGenerator.sol";
import "../Breed.sol";
import "./Random.sol";
import "lib/openzeppelin-contracts/contracts/access/Ownable.sol";

uint8 constant PIXELS_COUNT = 10;

contract Generator is Ownable(msg.sender) {
    using FilesLib for mapping(uint => Path[]);
    using PathLib for Path;
    using PathLib for Path[];
    using RandLib for Rand;
    using RandLib for string[];

    string[] public background_colors = [
        "#3498db",
        "#2ecc71",
        "#e74c3c",
        "#f39c12",
        "#9b59b6",
        "#e67e22",
        "#1abc9c",
        "#f1c40f",
        "#2980b9",
        "#ecf0f1"
    ];

    string[] public body_colors = [
        "#fad390",
        "#f8c291",
        "#6a89cc",
        "#82ccdd",
        "#b8e994",
        "#e55039",
        "#60a3bc",
        "#78e08f",
        "#fa983a",
        "#f6b93b"
    ];

    string[] public mouth_colors = [
        "#c0392b",
        "#e74c3c",
        "#e67e22",
        "#d35400",
        "#f39c12",
        "#2c3e50",
        "#27ae60",
        "#e74c3c",
        "#e67e22",
        "#f1c40f"
    ];

    string[] public shirt_1_colors = [
        "#1abc9c",
        "#2ecc71",
        "#3498db",
        "#9b59b6",
        "#e74c3c",
        "#f39c12",
        "#8e44ad",
        "#34495e",
        "#16a085",
        "#2980b9"
    ];

    string[] public shirt_2_colors = [
        "#27ae60",
        "#2980b9",
        "#e74c3c",
        "#f1c40f",
        "#8e44ad",
        "#d35400",
        "#2c3e50",
        "#16a085",
        "#f39c12",
        "#c0392b"
    ];

    string[] public eyes_colors = [
        "#f1c40f",
        "#e67e22",
        "#3498db",
        "#2ecc71",
        "#9b59b6",
        "#e74c3c",
        "#34495e",
        "#16a085",
        "#2980b9",
        "#f39c12"
    ];

    string[] public accessories_colors = [
        "#c0392b",
        "#16a085",
        "#f39c12",
        "#8e44ad",
        "#2ecc71",
        "#27ae60",
        "#2980b9",
        "#9b59b6",
        "#e74c3c",
        "#f1c40f"
    ];

    string[] public facial_hair_colors = [
        "#7f8c8d",
        "#34495e",
        "#2c3e50",
        "#8e44ad",
        "#c0392b",
        "#d35400",
        "#16a085",
        "#27ae60",
        "#2980b9",
        "#e67e22"
    ];

    string[] public eyes_base_colors = [
        "#2c3e50",
        "#f39c12",
        "#3498db",
        "#2ecc71",
        "#e74c3c",
        "#9b59b6",
        "#16a085",
        "#2980b9",
        "#f1c40f",
        "#d35400"
    ];

    string[] public hat_colors = [
        "#e74c3c",
        "#16a085",
        "#2ecc71",
        "#f39c12",
        "#3498db",
        "#8e44ad",
        "#c0392b",
        "#d35400",
        "#27ae60",
        "#9b59b6"
    ];

    mapping(uint => Path[]) body;
    mapping(uint => Path[]) facial_hair;
    mapping(uint => Path[]) shirt_1;
    mapping(uint => Path[]) shirt_2;
    mapping(uint => Path[]) mouth;
    mapping(uint => Path[]) eyes_base;
    mapping(uint => Path[]) eyes;
    mapping(uint => Path[]) hat;
    mapping(uint => Path[]) accessories;

    uint8 body_count;
    uint8 facial_hair_count;
    uint8 shirt_1_count;
    uint8 shirt_2_count;
    uint8 mouth_count;
    uint8 eyes_base_count;
    uint8 eyes_count;
    uint8 hat_count;
    uint8 accessories_count;
    uint color_step_base = 1000;
    uint MAX = 1000;

    function set_max_base(uint max) external onlyOwner {
        MAX = max;
    }

    function set_color_step_base(uint step_base) external onlyOwner {
        color_step_base = step_base;
    }

    function pick_0(uint count, uint random) internal pure returns (uint) {
        return random % count;
    }

    function pick_1(uint count, uint random) internal pure returns (uint) {
        return (random % count) + 1;
    }

    function get_step(uint breed2) internal view returns (uint) {
        if (breed2 < color_step_base) return color_step_base - breed2;
        return 1;
    }

    function pick_progressive(
        uint count,
        uint random
    ) internal pure returns (uint) {
        uint s = ((1 + count) * count) / 2;
        random %= s;
        uint sum;
        uint i;
        for (i = 0; i < count; ++i) {
            sum += i + 1;
            if (sum >= random) return count - i - 1;
        }
        return 0;
    }

    function pick_color_internal(
        uint count,
        uint random_value,
        uint step
    ) public pure returns (uint) {
        uint sum = 0;
        uint i;
        for (i = 0; i < count; ++i) sum += i * step + step;
        random_value = random_value % sum;
        sum = 0;
        for (i = 0; i < count; ++i) {
            sum += i * step + step;
            if (sum >= random_value) return i;
        }
        return 0;
    }

    function pick_color(
        string[] storage colors,
        uint random_value,
        uint step
    ) private view returns (uint) {
        return pick_color_internal(colors.length, random_value, step);
    }

    function get_item(
        Breed calldata breed
    ) external view returns (ItemData memory) {
        Rand memory rnd = Rand(breed, 0);

        ItemData memory data;
        data.background_color = rnd.next() % background_colors.length;
        data.body = pick_1(body_count, rnd.next());
        data.body_color = pick_color(
            body_colors,
            rnd.next(),
            get_step(rnd.breed.breed2)
        );
        if (rnd.next_breed2_clamped() > (MAX / 3)) {
            data.facial_hair = pick_1(facial_hair_count, rnd.next());
            data.facial_hair_color = pick_color(
                facial_hair_colors,
                rnd.next(),
                get_step(rnd.breed.breed2)
            );
        }
        data.shirt_1 = pick_1(shirt_1_count, rnd.next());
        data.shirt_1_color = rnd.next() % shirt_1_colors.length;
        if (rnd.next_breed2_clamped() > (MAX / 3)) {
            data.shirt_2 = pick_1(shirt_2_count, rnd.next());
            data.shirt_2_color = pick_color(
                shirt_2_colors,
                rnd.next(),
                get_step(rnd.breed.breed2)
            );
        }
        if (rnd.next_breed2_clamped() > (MAX / 3)) {
            data.mouth = pick_1(mouth_count, rnd.next());
            data.mouth_color = pick_color(
                mouth_colors,
                rnd.next(),
                get_step(rnd.breed.breed2)
            );
        }
        data.eyes_base_color = pick_color(
            eyes_base_colors,
            rnd.next(),
            get_step(rnd.breed.breed2)
        );
        data.eyes = pick_1(eyes_count, rnd.next());
        data.eyes_color = pick_color(
            eyes_colors,
            rnd.next(),
            get_step(rnd.breed.breed2)
        );
        if (rnd.next_breed2_clamped() > (MAX / 3)) {
            data.hat = pick_1(hat_count, rnd.next());
            data.hat_color = pick_color(
                hat_colors,
                rnd.next(),
                get_step(rnd.breed.breed2)
            );
        }
        if (rnd.next_breed2_clamped() > (MAX / 3)) {
            data.accessories = pick_1(accessories_count, rnd.next());
            data.accessories_color = pick_color(
                accessories_colors,
                rnd.next(),
                get_step(rnd.breed.breed2)
            );
        }

        return data;
    }

    function getSvg(
        Breed calldata breed
    ) external view returns (string memory) {
        return toSvg(this.get_item(breed));
    }

    function toSvg(ItemData memory data) internal view returns (string memory) {
        bytes memory svgStart = abi.encodePacked(
            "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0",
            " ",
            StringConverter.toString(PIXELS_COUNT),
            " ",
            StringConverter.toString(PIXELS_COUNT),
            "'>"
        );

        bytes memory b1 = abi.encodePacked(
            svgStart,
            abi.encodePacked(
                "<rect x='0' y='0'",
                " width='",
                StringConverter.toString(PIXELS_COUNT),
                "' height='",
                StringConverter.toString(PIXELS_COUNT),
                "' fill='",
                background_colors[data.background_color],
                "'/>"
            ),
            toSvg(body, body_colors, data.body, data.body_color),
            toSvg(shirt_1, shirt_1_colors, data.shirt_1, data.shirt_1_color),
            toSvg(
                facial_hair,
                facial_hair_colors,
                data.facial_hair,
                data.facial_hair_color
            ),
            toSvg(shirt_2, shirt_2_colors, data.shirt_2, data.shirt_2_color),
            toSvg(mouth, mouth_colors, data.mouth, data.mouth_color)
        );
        bytes memory b2 = abi.encodePacked(
            toSvg(eyes_base, eyes_base_colors, 1, data.eyes_base_color),
            toSvg(eyes, eyes_colors, data.eyes, data.eyes_color),
            toSvg(hat, hat_colors, data.hat, data.hat_color),
            toSvg_accessory(
                accessories,
                accessories_colors,
                data.accessories,
                data.accessories_color
            )
        );

        return string(abi.encodePacked(b1, b2, "</svg>"));
    }

    function toSvg(
        mapping(uint => Path[]) storage paths,
        string[] storage colors,
        uint item_id,
        uint color_index
    ) private view returns (string memory) {
        if (item_id == 0) return "";
        return paths[item_id - 1].toSvg(colors[color_index]);
    }

    function toSvg_accessory(
        mapping(uint => Path[]) storage paths,
        string[] storage colors,
        uint item_id,
        uint color_index
    ) private view returns (string memory) {
        if (item_id == 0) return "";
        if (item_id == 1) return paths[item_id - 1].toSvg();
        return paths[item_id - 1].toSvg(colors[color_index]);
    }
}

File 13 of 19 : Path.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "./Path.sol";
import "./String.sol";
import "./Colors.sol";
import "./Random.sol";

struct Path {
    string fill;
    string data;
}

library PathLib {
    using PathLib for Path;
    using RandLib for Rand;
    using RandLib for string[];
    using StringConverter for uint8;
    using ColorConvert for uint24;
    using StringLib for string;

    function toSvg(Path memory p) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked("<path fill='", p.fill, "' d='", p.data, "'/>")
            );
    }

    function toSvg(
        Path memory p,
        string memory color
    ) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "<path fill='",
                    color,
                    "' d='",
                    p.data,
                    color,
                    "'/>"
                )
            );
    }

    function toSvg(
        Path[] storage paths,
        string memory color
    ) internal view returns (string memory) {
        string memory res;
        for (uint i = 0; i < paths.length; ++i) {
            res = string(abi.encodePacked(res, paths[i].toSvg(color)));
        }
        return res;
    }

    function toSvg(Path[] storage paths) internal view returns (string memory) {
        string memory res;
        for (uint i = 0; i < paths.length; ++i) {
            res = string(abi.encodePacked(res, paths[i].toSvg()));
        }
        return res;
    }
}

File 14 of 19 : String.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

library StringLib {
    function equals(
        string memory s1,
        string memory s2
    ) internal pure returns (bool) {
        return (keccak256(abi.encodePacked((s1))) ==
            keccak256(abi.encodePacked((s2))));
    }
}

library StringConverter {
    function toString(uint value) internal pure returns (string memory) {
        if (value == 0) {
            return "0";
        }
        uint temp = value;
        uint digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
}

File 15 of 19 : Files.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import './Path.sol';

struct FileData {
    uint file;
    Path[] paths;
}

library FilesLib {
    function set_file(
        mapping(uint => Path[]) storage paths,
        FileData calldata input,
        uint8 count
    ) internal returns (uint8) {
        Path[] storage storageFile = paths[input.file];
        if (storageFile.length > 0) delete paths[input.file - 1];
        else ++count;
        for (uint i = 0; i < input.paths.length; ++i) {
            storageFile.push(input.paths[i]);
        }
        return count;
    }

    function set_files(
        mapping(uint => Path[]) storage paths,
        FileData[] calldata input,
        uint8 count
    ) internal returns (uint8) {
        if (input.length == 0) return count;
        uint i;
        for (i = 0; i < input.length; ++i)
            count = set_file(paths, input[i], count);
        return count;
    }
}

File 16 of 19 : Colors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

library ColorConvert {
    function toSvgColor(uint24 value) internal pure returns (string memory) {
        return string(abi.encodePacked("#", toHex(value)));
    }

    function toHex(uint24 value) internal pure returns (bytes memory) {
        bytes memory buffer = new bytes(6);
        for (uint i = 0; i < 3; ++i) {
            buffer[5 - i * 2] = hexChar(uint8(value) & 0x0f);
            buffer[4 - i * 2] = hexChar((uint8(value) >> 4) & 0x0f);
            value >>= 8;
        }
        return buffer;
    }

    function hexChar(uint8 value) internal pure returns (bytes1) {
        if (value < 10) return bytes1(uint8(48 + (uint(value) % 10)));
        return bytes1(uint8(65 + uint256((value - 10) % 6)));
    }
}

File 17 of 19 : IGenerator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../Breed.sol";
import "./ItemData.sol";

interface IGenerator {
    function get_item(
        Breed calldata seed_data
    ) external view returns (ItemData memory);

    function getSvg(
        Breed calldata seed_data
    ) external view returns (string memory);
}

File 18 of 19 : Random.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "../Breed.sol";

struct Rand {
    Breed breed;
    uint nonce;
}

library RandLib {
    function next(Rand memory rnd) internal pure returns (uint) {
        return
            uint(
                keccak256(
                    abi.encodePacked(
                        rnd.breed.serial_number,
                        rnd.breed.breed2,
                        rnd.nonce++
                    )
                )
            );
    }

    function next_breed2_clamped(Rand memory rnd) internal pure returns (uint) {
        return next(rnd) % rnd.breed.breed2;
    }
}

File 19 of 19 : ItemData.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

struct ItemData {
    uint background_color;
    uint body;
    uint body_color;
    uint facial_hair;
    uint facial_hair_color;
    uint shirt_1;
    uint shirt_1_color;
    uint shirt_2;
    uint shirt_2_color;
    uint shirt_3;
    uint shirt_3_color;
    uint nose;
    uint nose_color;
    uint mouth;
    uint mouth_color;
    uint eyes_base_color;
    uint eyes;
    uint eyes_color;
    uint hair;
    uint hair_color;
    uint hat;
    uint hat_color;
    uint accessories;
    uint accessories_color;
    uint mask;
    uint mask_color;
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "v2-core/=lib/v2-core/contracts/",
    "v2-periphery/=lib/v2-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"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":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"GEN_MIN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"accessories_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"uint256","name":"","type":"uint256"}],"name":"background_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"body_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"breed_total_count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"breeds","outputs":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"counts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"eyes_base_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"eyes_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"facial_hair_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gen_max","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"internalType":"struct Breed","name":"breed","type":"tuple"}],"name":"getSvg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_account_breeds","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"components":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"internalType":"struct Breed[]","name":"accounts","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_account_items","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"components":[{"internalType":"uint256","name":"background_color","type":"uint256"},{"internalType":"uint256","name":"body","type":"uint256"},{"internalType":"uint256","name":"body_color","type":"uint256"},{"internalType":"uint256","name":"facial_hair","type":"uint256"},{"internalType":"uint256","name":"facial_hair_color","type":"uint256"},{"internalType":"uint256","name":"shirt_1","type":"uint256"},{"internalType":"uint256","name":"shirt_1_color","type":"uint256"},{"internalType":"uint256","name":"shirt_2","type":"uint256"},{"internalType":"uint256","name":"shirt_2_color","type":"uint256"},{"internalType":"uint256","name":"shirt_3","type":"uint256"},{"internalType":"uint256","name":"shirt_3_color","type":"uint256"},{"internalType":"uint256","name":"nose","type":"uint256"},{"internalType":"uint256","name":"nose_color","type":"uint256"},{"internalType":"uint256","name":"mouth","type":"uint256"},{"internalType":"uint256","name":"mouth_color","type":"uint256"},{"internalType":"uint256","name":"eyes_base_color","type":"uint256"},{"internalType":"uint256","name":"eyes","type":"uint256"},{"internalType":"uint256","name":"eyes_color","type":"uint256"},{"internalType":"uint256","name":"hair","type":"uint256"},{"internalType":"uint256","name":"hair_color","type":"uint256"},{"internalType":"uint256","name":"hat","type":"uint256"},{"internalType":"uint256","name":"hat_color","type":"uint256"},{"internalType":"uint256","name":"accessories","type":"uint256"},{"internalType":"uint256","name":"accessories_color","type":"uint256"},{"internalType":"uint256","name":"mask","type":"uint256"},{"internalType":"uint256","name":"mask_color","type":"uint256"}],"internalType":"struct ItemData[]","name":"accounts","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_account_svgs","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"internalType":"string[]","name":"accounts","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"get_holders_list","outputs":[{"internalType":"uint256","name":"page_count","type":"uint256"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"serial_number","type":"uint256"},{"internalType":"uint256","name":"breed2","type":"uint256"}],"internalType":"struct Breed","name":"breed","type":"tuple"}],"name":"get_item","outputs":[{"components":[{"internalType":"uint256","name":"background_color","type":"uint256"},{"internalType":"uint256","name":"body","type":"uint256"},{"internalType":"uint256","name":"body_color","type":"uint256"},{"internalType":"uint256","name":"facial_hair","type":"uint256"},{"internalType":"uint256","name":"facial_hair_color","type":"uint256"},{"internalType":"uint256","name":"shirt_1","type":"uint256"},{"internalType":"uint256","name":"shirt_1_color","type":"uint256"},{"internalType":"uint256","name":"shirt_2","type":"uint256"},{"internalType":"uint256","name":"shirt_2_color","type":"uint256"},{"internalType":"uint256","name":"shirt_3","type":"uint256"},{"internalType":"uint256","name":"shirt_3_color","type":"uint256"},{"internalType":"uint256","name":"nose","type":"uint256"},{"internalType":"uint256","name":"nose_color","type":"uint256"},{"internalType":"uint256","name":"mouth","type":"uint256"},{"internalType":"uint256","name":"mouth_color","type":"uint256"},{"internalType":"uint256","name":"eyes_base_color","type":"uint256"},{"internalType":"uint256","name":"eyes","type":"uint256"},{"internalType":"uint256","name":"eyes_color","type":"uint256"},{"internalType":"uint256","name":"hair","type":"uint256"},{"internalType":"uint256","name":"hair_color","type":"uint256"},{"internalType":"uint256","name":"hat","type":"uint256"},{"internalType":"uint256","name":"hat_color","type":"uint256"},{"internalType":"uint256","name":"accessories","type":"uint256"},{"internalType":"uint256","name":"accessories_color","type":"uint256"},{"internalType":"uint256","name":"mask","type":"uint256"},{"internalType":"uint256","name":"mask_color","type":"uint256"}],"internalType":"struct ItemData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"get_item_acc_index","outputs":[{"components":[{"internalType":"uint256","name":"background_color","type":"uint256"},{"internalType":"uint256","name":"body","type":"uint256"},{"internalType":"uint256","name":"body_color","type":"uint256"},{"internalType":"uint256","name":"facial_hair","type":"uint256"},{"internalType":"uint256","name":"facial_hair_color","type":"uint256"},{"internalType":"uint256","name":"shirt_1","type":"uint256"},{"internalType":"uint256","name":"shirt_1_color","type":"uint256"},{"internalType":"uint256","name":"shirt_2","type":"uint256"},{"internalType":"uint256","name":"shirt_2_color","type":"uint256"},{"internalType":"uint256","name":"shirt_3","type":"uint256"},{"internalType":"uint256","name":"shirt_3_color","type":"uint256"},{"internalType":"uint256","name":"nose","type":"uint256"},{"internalType":"uint256","name":"nose_color","type":"uint256"},{"internalType":"uint256","name":"mouth","type":"uint256"},{"internalType":"uint256","name":"mouth_color","type":"uint256"},{"internalType":"uint256","name":"eyes_base_color","type":"uint256"},{"internalType":"uint256","name":"eyes","type":"uint256"},{"internalType":"uint256","name":"eyes_color","type":"uint256"},{"internalType":"uint256","name":"hair","type":"uint256"},{"internalType":"uint256","name":"hair_color","type":"uint256"},{"internalType":"uint256","name":"hat","type":"uint256"},{"internalType":"uint256","name":"hat_color","type":"uint256"},{"internalType":"uint256","name":"accessories","type":"uint256"},{"internalType":"uint256","name":"accessories_color","type":"uint256"},{"internalType":"uint256","name":"mask","type":"uint256"},{"internalType":"uint256","name":"mask_color","type":"uint256"}],"internalType":"struct ItemData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"get_svg_acc_index","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hat_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"holders_count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"max_breed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mouth_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"count","type":"uint256"},{"internalType":"uint256","name":"random_value","type":"uint256"},{"internalType":"uint256","name":"step","type":"uint256"}],"name":"pick_color_internal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"step_base","type":"uint256"}],"name":"set_color_step_base","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"set_max_base","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"shirt_1_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"shirt_2_colors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","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":"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":"index","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"transfer_breed_from_to_by_index","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60076101e08181526611999a1c9c323160c91b6102005260a0908152610220828152662332656363373160c81b6102405260c052610260828152662365373463336360c81b6102805260e0526102a08281526611b3199cb1989960c91b6102c052610100526102e082815266119cb11a9cb11b60c91b61030052610120526103208281526611b29b1bb2991960c91b6103405261014052610360828152662331616263396360c81b61038052610160526103a08281526611b318b19a183360c91b6103c052610180526103e0828152662332393830623960c81b610400526101a052610460604052610420918252662365636630663160c81b610440526101c09190915261011190600690600a610f7d565b50604080516101808101825260076101408201818152660236661643339360cc1b610160840152825282518084018452818152662366386332393160c81b6020828101919091528084019190915283518085018552828152662336613839636360c81b8183015283850152835180850185528281526608ce0c98d8d91960ca1b818301526060840152835180850185528281526608d88e194e4e4d60ca1b81830152608084015283518085018552828152662365353530333960c81b8183015260a084015283518085018552828152662336306133626360c81b8183015260c08401528351808501855282815266119b9c32981c3360c91b8183015260e084015283518085018552828152662366613938336160c81b8183015261010084015283518085019094528184526611b31b311c99b160c91b908401526101208201929092526102609190600a610f7d565b506040805161018081018252600761014082018181526611b198199c993160c91b610160840152825282518084018452818152662365373463336360c81b602082810182905280850192909252845180860186528381526611b29b1bb2991960c91b8184018190528587019190915285518087018752848152660236433353430360cc1b818501526060860152855180870187528481526611b3199cb1989960c91b81850152608086015285518087018752848152660233263336535360cc1b8185015260a086015285518087018752848152660233237616536360cc1b8185015260c0860152855180870187528481528084019290925260e0850191909152845180860186528381528083019190915261010084015283518085019094529083526611b318b19a183360c91b908301526101208101919091526103a890600890600a610f7d565b50604080516101808101825260076101408201818152662331616263396360c81b610160840152825282518084018452818152662332656363373160c81b60208281019190915280840191909152835180850185528281526611999a1c9c323160c91b81830152838501528351808501855282815266119cb11a9cb11b60c91b81830152606084015283518085018552828152662365373463336360c81b818301526080840152835180850185528281526611b3199cb1989960c91b8183015260a0840152835180850185528281526608ce194d0d185960ca1b8183015260c084015283518085018552828152662333343439356560c81b8183015260e084015283518085018552828152662331366130383560c81b818301526101008401528351808501909452908352662332393830623960c81b908301526101208101919091526104f990600990600a610f7d565b50604080516101808101825260076101408201818152660233237616536360cc1b610160840152825282518084018452818152662332393830623960c81b6020828101919091528084019190915283518085018552828152662365373463336360c81b8183015283850152835180850185528281526611b318b19a183360c91b818301526060840152835180850185528281526608ce194d0d185960ca1b81830152608084015283518085018552828152660236433353430360cc1b8183015260a084015283518085018552828152660233263336535360cc1b8183015260c084015283518085018552828152662331366130383560c81b8183015260e0840152835180850185528281526611b3199cb1989960c91b8183015261010084015283518085019094529083526611b198199c993160c91b9083015261012081019190915261064990600a9081610f7d565b506040805161018081018252600761014082018181526611b318b19a183360c91b6101608401528252825180840184528181526611b29b1bb2991960c91b60208281019190915280840191909152835180850185528281526611999a1c9c323160c91b818301528385015283518085018552828152662332656363373160c81b8183015260608401528351808501855282815266119cb11a9cb11b60c91b81830152608084015283518085018552828152662365373463336360c81b8183015260a084015283518085018552828152662333343439356560c81b8183015260c084015283518085018552828152662331366130383560c81b8183015260e084015283518085018552828152662332393830623960c81b8183015261010084015283518085019094529083526611b3199cb1989960c91b9083015261012081019190915261079a90600b90600a610f7d565b506040805161018081018252600761014082018181526611b198199c993160c91b610160840152825282518084018452818152662331366130383560c81b60208281019190915280840191909152835180850185528281526611b3199cb1989960c91b8183015283850152835180850185528281526608ce194d0d185960ca1b81830152606084015283518085018552828152662332656363373160c81b81830152608084015283518085018552828152660233237616536360cc1b8183015260a084015283518085018552828152662332393830623960c81b8183015260c08401528351808501855282815266119cb11a9cb11b60c91b8183015260e084015283518085018552828152662365373463336360c81b8183015261010084015283518085019094529083526611b318b19a183360c91b908301526101208101919091526108eb90600c90600a610f7d565b506040805161018081018252600761014082018181526608cdd98e18ce1960ca1b610160840152825282518084018452818152662333343439356560c81b6020828101919091528084019190915283518085018552828152660233263336535360cc1b8183015283850152835180850185528281526608ce194d0d185960ca1b818301526060840152835180850185528281526611b198199c993160c91b81830152608084015283518085018552828152660236433353430360cc1b8183015260a084015283518085018552828152662331366130383560c81b8183015260c084015283518085018552828152660233237616536360cc1b8183015260e084015283518085018552828152662332393830623960c81b8183015261010084015283518085019094529083526611b29b1bb2991960c91b90830152610120810191909152610a3c90600d90600a610f7d565b50604080516101808101825260076101408201818152660233263336535360cc1b6101608401528252825180840184528181526611b3199cb1989960c91b60208281019190915280840191909152835180850185528281526611999a1c9c323160c91b818301528385015283518085018552828152662332656363373160c81b81830152606084015283518085018552828152662365373463336360c81b8183015260808401528351808501855282815266119cb11a9cb11b60c91b8183015260a084015283518085018552828152662331366130383560c81b8183015260c084015283518085018552828152662332393830623960c81b8183015260e0840152835180850185528281526611b318b19a183360c91b818301526101008401528351808501909452908352660236433353430360cc1b90830152610120810191909152610b8d90600e90600a610f7d565b50604080516101808101825260076101408201818152662365373463336360c81b610160840152825282518084018452818152662331366130383560c81b6020828101919091528084019190915283518085018552828152662332656363373160c81b8183015283850152835180850185528281526611b3199cb1989960c91b818301526060840152835180850185528281526611999a1c9c323160c91b818301526080840152835180850185528281526608ce194d0d185960ca1b8183015260a0840152835180850185528281526611b198199c993160c91b8183015260c084015283518085018552828152660236433353430360cc1b8183015260e084015283518085018552828152660233237616536360cc1b81830152610100840152835180850190945290835266119cb11a9cb11b60c91b90830152610120810191909152610cde90600f90600a610f7d565b506103e8601a556103e8601b556103e8602255348015610cfd57600080fd5b5060405180604001604052806008815260200167416c74686569736d60c01b815250604051806040016040528060018152602001604160f81b8152503382828160039081610d4b91906110e3565b506004610d5882826110e3565b5050506001600160a01b038116610d8a57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b610d9381610dc7565b50336080819052610dbb90610daa6009600a61129e565b610db6906103e86112b4565b610e19565b50506001601e556112de565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038216610e435760405163ec442f0560e01b815260006004820152602401610d81565b610e4f60008383610e53565b5050565b6001600160a01b038316610e7e578060026000828254610e7391906112cb565b90915550610ef09050565b6001600160a01b03831660009081526020819052604090205481811015610ed15760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610d81565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610f0c57600280548290039055610f2b565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610f7091815260200190565b60405180910390a3505050565b828054828255906000526020600020908101928215610fc3579160200282015b82811115610fc35782518290610fb390826110e3565b5091602001919060010190610f9d565b50610fcf929150610fd3565b5090565b80821115610fcf576000610fe78282610ff0565b50600101610fd3565b508054610ffc90611058565b6000825580601f1061100c575050565b601f01602090049060005260206000209081019061102a919061102d565b50565b5b80821115610fcf576000815560010161102e565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061106c57607f821691505b60208210810361108c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156110de576000816000526020600020601f850160051c810160208610156110bb5750805b601f850160051c820191505b818110156110da578281556001016110c7565b5050505b505050565b81516001600160401b038111156110fc576110fc611042565b6111108161110a8454611058565b84611092565b602080601f831160018114611145576000841561112d5750858301515b600019600386901b1c1916600185901b1785556110da565b600085815260208120601f198616915b8281101561117457888601518255948401946001909101908401611155565b50858210156111925787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156111f35781600019048211156111d9576111d96111a2565b808516156111e657918102915b93841c93908002906111bd565b509250929050565b60008261120a57506001611298565b8161121757506000611298565b816001811461122d576002811461123757611253565b6001915050611298565b60ff841115611248576112486111a2565b50506001821b611298565b5060208310610133831016604e8410600b8410161715611276575081810a611298565b61128083836111b8565b8060001904821115611294576112946111a2565b0290505b92915050565b60006112ad60ff8416836111fb565b9392505050565b8082028115828204841417611298576112986111a2565b80820180821115611298576112986111a2565b608051613b9b6113076000396000818161027f015281816118af01526118eb0152613b9b6000f3fe6080604052600436106102765760003560e01c806374ae51361161014f578063b42781ee116100c1578063dd0b281e1161007a578063dd0b281e14610886578063dd62ed3e146108a6578063dde415fa14610733578063e7a966b6146108ec578063f2fde38b1461090c578063f578990e1461092c57600080fd5b8063b42781ee146107c2578063b42dfa0d146107e2578063b4377a3e146107f8578063b4f243a414610818578063c01e21af14610838578063d5a426061461085857600080fd5b80638da5cb5b116101135780638da5cb5b1461070b5780638fdada4a1461073357806395d89b411461074957806398bafaa31461075e578063a9059cbb1461078c578063af504def146107ac57600080fd5b806374ae51361461065d578063750e8d101461067d5780637673bfa4146106ab5780637c3b3b87146106cb57806387cd1555146106eb57600080fd5b80633860a393116101e85780635534b159116101ac5780635534b159146105695780635e927ceb146105895780636a29f5e5146105a957806370a08231146105fd57806370db69d614610633578063715018a61461064857600080fd5b80633860a393146104ae5780633fc0fdcb146104dc578063422b9e231461050957806353388fd514610529578063544736e61461054957600080fd5b80630dfa2c481161023a5780630dfa2c481461040857806318160ddd1461042857806323b872dd1461043d5780632547b84d1461045d5780632d12d34b1461047d578063313ce5671461049257600080fd5b8063018a3741146103405780630568e65e1461036957806306a86dd71461039657806306fdde03146103c3578063095ea7b3146103d857600080fd5b3661033b5760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163460405160006040518083038185875af1925050503d80600081146102e8576040519150601f19603f3d011682016040523d82523d6000602084013e6102ed565b606091505b505080915050806103395760405162461bcd60e51b815260206004820152601160248201527031b0b7103737ba1033b2ba1032ba3432b960791b60448201526064015b60405180910390fd5b005b600080fd5b34801561034c57600080fd5b5061035660215481565b6040519081526020015b60405180910390f35b34801561037557600080fd5b50610356610384366004612ef4565b60246020526000908152604090205481565b3480156103a257600080fd5b506103b66103b1366004612f0f565b61094c565b6040516103609190612f78565b3480156103cf57600080fd5b506103b66109f8565b3480156103e457600080fd5b506103f86103f3366004612f8b565b610a8a565b6040519015158152602001610360565b34801561041457600080fd5b506103b6610423366004612f0f565b610aa4565b34801561043457600080fd5b50600254610356565b34801561044957600080fd5b506103f8610458366004612fb5565b610ab4565b34801561046957600080fd5b506103b6610478366004612f0f565b610ada565b34801561048957600080fd5b50610356600181565b34801561049e57600080fd5b5060405160098152602001610360565b3480156104ba57600080fd5b506104ce6104c9366004612ff1565b610aea565b604051610360929190613013565b3480156104e857600080fd5b506104fc6104f7366004612f8b565b610bf2565b604051610360919061317d565b34801561051557600080fd5b506103b661052436600461318c565b610c8a565b34801561053557600080fd5b506103b6610544366004612f0f565b610d02565b34801561055557600080fd5b50601c546001600160a01b031615156103f8565b34801561057557600080fd5b506103b6610584366004612f0f565b610d12565b34801561059557600080fd5b506103396105a4366004612f0f565b610d22565b3480156105b557600080fd5b506105e86105c4366004612f8b565b60236020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610360565b34801561060957600080fd5b50610356610618366004612ef4565b6001600160a01b031660009081526020819052604090205490565b34801561063f57600080fd5b50610356610d2f565b34801561065457600080fd5b50610339610e2c565b34801561066957600080fd5b506103b6610678366004612f0f565b610e40565b34801561068957600080fd5b5061069d6106983660046131a4565b610e50565b6040516103609291906131d7565b3480156106b757600080fd5b506103b66106c6366004612f0f565b61100c565b3480156106d757600080fd5b506104fc6106e636600461318c565b61101c565b3480156106f757600080fd5b506103b6610706366004612f0f565b6112e0565b34801561071757600080fd5b506005546040516001600160a01b039091168152602001610360565b34801561073f57600080fd5b506103566103e881565b34801561075557600080fd5b506103b66112f0565b34801561076a57600080fd5b5061077e6107793660046131a4565b6112ff565b604051610360929190613225565b34801561079857600080fd5b506103f86107a7366004612f8b565b61146f565b3480156107b857600080fd5b5061035660255481565b3480156107ce57600080fd5b506103396107dd366004612f0f565b61147d565b3480156107ee57600080fd5b5061035660225481565b34801561080457600080fd5b50610339610813366004613280565b61148a565b34801561082457600080fd5b506103b6610833366004612f8b565b6114e9565b34801561084457600080fd5b506103566108533660046132ac565b611523565b34801561086457600080fd5b506108786108733660046131a4565b6115bb565b6040516103609291906132d8565b34801561089257600080fd5b506103396108a1366004612ef4565b611729565b3480156108b257600080fd5b506103566108c1366004613344565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156108f857600080fd5b506103b6610907366004612f0f565b611757565b34801561091857600080fd5b50610339610927366004612ef4565b611767565b34801561093857600080fd5b506103b6610947366004612f0f565b6117a5565b6007818154811061095c57600080fd5b9060005260206000200160009150905080546109779061336e565b80601f01602080910402602001604051908101604052809291908181526020018280546109a39061336e565b80156109f05780601f106109c5576101008083540402835291602001916109f0565b820191906000526020600020905b8154815290600101906020018083116109d357829003601f168201915b505050505081565b606060038054610a079061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054610a339061336e565b8015610a805780601f10610a5557610100808354040283529160200191610a80565b820191906000526020600020905b815481529060010190602001808311610a6357829003601f168201915b5050505050905090565b600033610a988185856117b5565b60019150505b92915050565b6009818154811061095c57600080fd5b600033610ac28582856117c7565b610acd858585611845565b60019150505b9392505050565b600d818154811061095c57600080fd5b600060606021548410610b0e57505060408051600080825260208201909252610beb565b6000610b1a84866133ce565b9050602154811115610b2b57506021545b610b3585826133e1565b92508267ffffffffffffffff811115610b5057610b506133a2565b604051908082528060200260200182016040528015610b79578160200160208202803683370190505b509150845b83811015610be857601f6000610b9483896133ce565b815260200190815260200160002060009054906101000a90046001600160a01b0316838281518110610bc857610bc86133f4565b6001600160a01b0390921660209283029190910190910152600101610b7e565b50505b9250929050565b610bfa612e1a565b6001600160a01b0383166000908152602360209081526040808320858452909152908190209051637c3b3b8760e01b81528154600482015260019091015460248201523090637c3b3b879060440161034060405180830381865afa158015610c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad39190613442565b604051637c3b3b8760e01b81528135600482015260208201356024820152606090610a9e903090637c3b3b87906044015b61034060405180830381865afa158015610cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfd9190613442565b611997565b6008818154811061095c57600080fd5b600f818154811061095c57600080fd5b610d2a611b71565b601b55565b6000610d45601c546001600160a01b0316151590565b610d6657610d556009600a61365a565b610d61906103e8613669565b905090565b60006127106001601d5442610d7b91906133e1565b610d876009600a61365a565b610d93906103e8613669565b610d9d9190613669565b610da79190613669565b610db19190613696565b612710610dc06009600a61365a565b610dcc906103e8613669565b610dd7906005613669565b610de19190613696565b610deb91906133ce565b9050610df96009600a61365a565b610e05906103e8613669565b811115610e2757610e186009600a61365a565b610e24906103e8613669565b90505b919050565b610e34611b71565b610e3e6000611b9e565b565b600b818154811061095c57600080fd5b6001600160a01b038316600090815260246020526040812054606090808510610eaf576040805160008082526020820190925281610ea4565b610e91612e1a565b815260200190600190039081610e895790505b509250925050611004565b6000610ebb85876133ce565b905081811115610ec85750805b610ed286826133e1565b93508367ffffffffffffffff811115610eed57610eed6133a2565b604051908082528060200260200182016040528015610f2657816020015b610f13612e1a565b815260200190600190039081610f0b5790505b50925060005b84811015611000576001600160a01b03881660009081526023602052604081203091637c3b3b879190610f5f858c6133ce565b81526020019081526020016000206040518263ffffffff1660e01b8152600401610f99919081548152600190910154602082015260400190565b61034060405180830381865afa158015610fb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdb9190613442565b848281518110610fed57610fed6133f4565b6020908102919091010152600101610f2c565b5050505b935093915050565b6006818154811061095c57600080fd5b611024612e1a565b600060405180604001604052808480360381019061104291906136aa565b815260200160008152509050611056612e1a565b60065461106283611bf0565b61106c9190613707565b81526019546110869060ff1661108184611bf0565b611c46565b60208201526110ad600761109984611bf0565b8451602001516110a890611c5d565b611c7f565b6040820152601b546110c190600390613696565b6110ca83611c97565b1115611101576019546110e890610100900460ff1661108184611bf0565b60608201526110fb600d61109984611bf0565b60808201525b60195461111a9062010000900460ff1661108184611bf0565b60a082015260095461112b83611bf0565b6111359190613707565b60c0820152601b5461114990600390613696565b61115283611c97565b111561118c57601954611172906301000000900460ff1661108184611bf0565b60e0820152611185600a61109984611bf0565b6101008201525b6003601b5461119b9190613696565b6111a483611c97565b11156111e0576019546111c590640100000000900460ff1661108184611bf0565b6101a08201526111d9600861109984611bf0565b6101c08201525b6111ee600e61109984611bf0565b6101e0820152601954611211906601000000000000900460ff1661108184611bf0565b610200820152611225600b61109984611bf0565b610220820152601b5461123a90600390613696565b61124383611c97565b11156112825760195461126790670100000000000000900460ff1661108184611bf0565b61028082015261127b600f61109984611bf0565b6102a08201525b6003601b546112919190613696565b61129a83611c97565b1115610ad3576019546112bf9068010000000000000000900460ff1661108184611bf0565b6102c08201526112d3600c61109984611bf0565b6102e08201529392505050565b600e818154811061095c57600080fd5b606060048054610a079061336e565b6001600160a01b038316600090815260246020526040812054606090808510611369576040805160008082526020820190925281610ea4565b6040805180820190915260008082526020820152815260200190600190039081611338579050509250925050611004565b600061137585876133ce565b9050818111156113825750805b61138c86826133e1565b93508367ffffffffffffffff8111156113a7576113a76133a2565b6040519080825280602002602001820160405280156113ec57816020015b60408051808201909152600080825260208201528152602001906001900390816113c55790505b50925060005b84811015611000576001600160a01b03881660009081526023602052604081209061141d838a6133ce565b81526020019081526020016000206040518060400160405290816000820154815260200160018201548152505084828151811061145c5761145c6133f4565b60209081029190910101526001016113f2565b600033610a98818585611845565b611485611b71565b601a55565b3360009081526024602052604090205482106114da5760405162461bcd60e51b815260206004820152600f60248201526e0d2dcc6dee4e4cac6e840d2dcc8caf608b1b6044820152606401610330565b6114e5338383611cb3565b5050565b604051633fc0fdcb60e01b81526001600160a01b038316600482015260248101829052606090610ad3903090633fc0fdcb90604401610cbb565b600080805b85811015611559578361153b8183613669565b61154591906133ce565b61154f90836133ce565b9150600101611528565b6115638286613707565b945060009150600090505b858110156115af57836115818183613669565b61158b91906133ce565b61159590836133ce565b91508482106115a7579150610ad39050565b60010161156e565b50600095945050505050565b6001600160a01b038316600090815260246020526040812054606090808510611613576040805160008082526020820190925281610ea4565b60608152602001906001900390816115f4579050509250925050611004565b600061161f85876133ce565b90508181111561163857508061163581876133e1565b93505b8367ffffffffffffffff811115611651576116516133a2565b60405190808252806020026020018201604052801561168457816020015b606081526020019060019003908161166f5790505b5092508560005b8282101561171d576001600160a01b0389166000908152602360209081526040808320858452909152908190209051637c3b3b8760e01b81528154600482015260019091015460248201526116ea903090637c3b3b8790604401610cbb565b85826116f58161371b565b935081518110611707576117076133f4565b602002602001018190525081600101915061168b565b50505050935093915050565b611731611b71565b601c80546001600160a01b0319166001600160a01b039290921691909117905542601d55565b600c818154811061095c57600080fd5b61176f611b71565b6001600160a01b03811661179957604051631e4fbdf760e01b815260006004820152602401610330565b6117a281611b9e565b50565b600a818154811061095c57600080fd5b6117c28383836001611d15565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461183f578181101561183057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610330565b61183f84848484036000611d15565b50505050565b6001600160a01b038216158061186557506001600160a01b03821661dead145b15611875576117c2838383611dea565b601c546001600160a01b031615801561191f57506001600160a01b03831615806118a757506001600160a01b03831630145b806118e357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316145b8061191f57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316145b1561192f576117c283838361202e565b601c54600160a01b900460ff161561194c576117c283838361202e565b601c546001600160a01b039081169084160361196c576117c2828261208d565b601c546001600160a01b039081169083160361198c576117c28382612160565b6117c2838383611dea565b606060006119a5600a61227d565b6119af600a61227d565b6040516020016119c0929190613734565b60408051601f1981840301815291905290506000816119df600a61227d565b6119e9600a61227d565b6006876000015181548110611a0057611a006133f4565b90600052602060002001604051602001611a1c939291906137cf565b604051602081830303815290604052611a41601060078860200151896040015161237e565b611a57601260098960a001518a60c0015161237e565b611a6d6011600d8a606001518b6080015161237e565b611a846013600a8b60e001518c610100015161237e565b611a9c601460088c6101a001518d6101c0015161237e565b604051602001611ab2979695949392919061390f565b60405160208183030381529060405290506000611ad96015600e6001886101e0015161237e565b611af16016600b88610200015189610220015161237e565b611b096017600f8961028001518a6102a0015161237e565b611b216018600c8a6102c001518b6102e0015161247a565b604051602001611b3494939291906139a1565b60405160208183030381529060405290508181604051602001611b589291906139f8565b6040516020818303038152906040529350505050919050565b6005546001600160a01b03163314610e3e5760405163118cdaa760e01b8152336004820152602401610330565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80518051602091820151918301805160009391611c0c8261371b565b9052604080516020810194909452830191909152606082015260800160408051601f19818403018152919052805160209091012092915050565b6000611c528383613707565b610ad39060016133ce565b6000601a54821015611c775781601a54610a9e91906133e1565b506001919050565b8254600090611c8f908484611523565b949350505050565b805160200151600090611ca983611bf0565b610a9e9190613707565b6001600160a01b03831660009081526023602090815260408083208584528252918290208251808401909352805483526001015490820152611d018483611cfc6009600a61365a565b6124cc565b611d0b8484612530565b61183f828261263a565b6001600160a01b038416611d3f5760405163e602df0560e01b815260006004820152602401610330565b6001600160a01b038316611d6957604051634a1406b160e11b815260006004820152602401610330565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561183f57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051611ddc91815260200190565b60405180910390a350505050565b611df26126ff565b6001600160a01b03831660009081526020819052604081205490611e1683836133e1565b90506000611e39856001600160a01b031660009081526020819052604090205490565b90506000611e4785836133ce565b90506001600160a01b0386161580611e6957506001600160a01b03861661dead145b15611e75575060009050805b6000611e836009600a61365a565b611e8d9085613696565b611e996009600a61365a565b611ea39087613696565b611ead91906133e1565b90506000611ebd6009600a61365a565b611ec79085613696565b611ed36009600a61365a565b611edd9085613696565b611ee791906133e1565b90508181811115611ef55750805b6001600160a01b038a166000908152602460205260408120545b82821015611f87578015611f87576000611f2882613a38565b6001600160a01b038e1660009081526023602090815260408083208484528252918290208251808401909352805483526001015490820152909250829150611f708e83612530565b611f7a8d8261263a565b5050816001019150611f0f565b82915b85831015611fb8576000611f9d83613a38565b9250829050611fac8e82612530565b50826001019250611f8a565b8092505b8483101561200f5760006040518060400160405280602660008154611fe09061371b565b91829055508152602001611ff56103e8612729565b905290506120038d8261263a565b50826001019250611fbc565b61201a8d8d8d6124cc565b505050505050505050506117c26001601e55565b6001600160a01b03831661205857604051634b637e8f60e11b815260006004820152602401610330565b6001600160a01b0382166120825760405163ec442f0560e01b815260006004820152602401610330565b6117c2838383612778565b6120956126ff565b6001600160a01b038216600090815260208190526040812054906120b983836133ce565b905060006120c96009600a61365a565b6120d39084613696565b6120df6009600a61365a565b6120e99084613696565b6120f391906133e1565b905060005b81811015612148576000604051806040016040528060266000815461211c9061371b565b918290555081526020016121316103e8612729565b9052905061213f878261263a565b506001016120f8565b61215286866128a2565b505050506114e56001601e55565b601c805460ff60a01b1916600160a01b17905561217b6126ff565b6001600160a01b0382166000908152602081905260408120549061219f83836133e1565b905060006121af6009600a61365a565b6121b99083613696565b6121c56009600a61365a565b6121cf9085613696565b6121d991906133e1565b6001600160a01b038616600090815260246020526040812054919250905b82821015612245576103e8602254101561221f5760226000815461221a9061371b565b909155505b801561223a5761223a8761223283613a38565b925082612530565b8160010191506121f7565b601c5461225d9088906001600160a01b031688611845565b505050505061226c6001601e55565b5050601c805460ff60a01b19169055565b6060816000036122a45750506040805180820190915260018152600360fc1b602082015290565b8160005b81156122ce57806122b88161371b565b91506122c79050600a83613696565b91506122a8565b60008167ffffffffffffffff8111156122e9576122e96133a2565b6040519080825280601f01601f191660200182016040528015612313576020820181803683370190505b5090505b8415611c8f576123286001836133e1565b9150612335600a86613707565b6123409060306133ce565b60f81b818381518110612355576123556133f4565b60200101906001600160f81b031916908160001a905350612377600a86613696565b9450612317565b60608260000361239d5750604080516020810190915260008152611c8f565b6124718483815481106123b2576123b26133f4565b9060005260206000200180546123c79061336e565b80601f01602080910402602001604051908101604052809291908181526020018280546123f39061336e565b80156124405780601f1061241557610100808354040283529160200191612440565b820191906000526020600020905b81548152906001019060200180831161242357829003601f168201915b505050505086600060018761245591906133e1565b815260200190815260200160002061290d90919063ffffffff16565b95945050505050565b6060826000036124995750604080516020810190915260008152611c8f565b8260010361239d576124c58560006124b26001876133e1565b8152602001908152602001600020612ab1565b9050611c8f565b601c805460ff60a01b1916600160a01b1790556001600160a01b03821615806124ff57506001600160a01b03821661dead145b156125135761250e8382612c4a565b61251e565b61251e83838361202e565b5050601c805460ff60a01b1916905550565b601c546001600160a01b039081169083160361254a575050565b6001600160a01b0382166000908152602460205260408120805490919061257090613a38565b91829055506000036125855761258582612c80565b60256000815461259490613a38565b909155506001600160a01b038216600090815260246020526040902054818114612608576001600160a01b0383166000908152602360209081526040808320848452808352818420825180840184528154815260019182015481860190815288875292909452919093209151825591519101555b6001600160a01b0390921660009081526023602090815260408083209483529390529182208281556001019190915550565b601c546001600160a01b0390811690831603612654575050565b6001600160a01b0382166000908152602460205260408120805490919061267a9061371b565b918290555060010361268f5761268f82612d62565b60256000815461269e9061371b565b909155506001600160a01b0382166000908152602460205260408120546126c7906001906133e1565b6001600160a01b0393909316600090815260236020908152604080832095835294815293902082518155919092015160019091015550565b6002601e540361272257604051633ee5aeb560e01b815260040160405180910390fd5b6002601e55565b60006103e86022548361273c9190613669565b6127469190613696565b91508160000361275557600191505b600160225411156127745760226000815461276f90613a38565b909155505b5090565b6001600160a01b0383166127a357806002600082825461279891906133ce565b909155506128159050565b6001600160a01b038316600090815260208190526040902054818110156127f65760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610330565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661283157600280548290039055612850565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161289591815260200190565b60405180910390a3505050565b806128ab610d2f565b8111156128e45760405162461bcd60e51b81526020600482015260076024820152666d61782062757960c81b6044820152606401610330565b601c805460ff60a01b198116600160a01b1790915561251e906001600160a01b0316848461202e565b60608060005b8454811015612aa95781612a7e85878481548110612933576129336133f4565b906000526020600020906002020160405180604001604052908160008201805461295c9061336e565b80601f01602080910402602001604051908101604052809291908181526020018280546129889061336e565b80156129d55780601f106129aa576101008083540402835291602001916129d5565b820191906000526020600020905b8154815290600101906020018083116129b857829003601f168201915b505050505081526020016001820180546129ee9061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054612a1a9061336e565b8015612a675780601f10612a3c57610100808354040283529160200191612a67565b820191906000526020600020905b815481529060010190602001808311612a4a57829003601f168201915b505050505081525050612db590919063ffffffff16565b604051602001612a8f929190613a4f565b60408051601f198184030181529190529150600101612913565b509392505050565b60608060005b8354811015612c435781612c18858381548110612ad657612ad66133f4565b9060005260206000209060020201604051806040016040529081600082018054612aff9061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054612b2b9061336e565b8015612b785780601f10612b4d57610100808354040283529160200191612b78565b820191906000526020600020905b815481529060010190602001808311612b5b57829003601f168201915b50505050508152602001600182018054612b919061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054612bbd9061336e565b8015612c0a5780601f10612bdf57610100808354040283529160200191612c0a565b820191906000526020600020905b815481529060010190602001808311612bed57829003601f168201915b505050505081525050612de7565b604051602001612c29929190613a4f565b60408051601f198184030181529190529150600101612ab7565b5092915050565b6001600160a01b038216612c7457604051634b637e8f60e11b815260006004820152602401610330565b6114e582600083612778565b602154600003612c8d5750565b6001600160a01b0381166000908152602080526040902054602154612cb4906001906133e1565b8114612d17576000601f60006001602154612ccf91906133e1565b81526020808201929092526040908101600090812054858252601f845282822080546001600160a01b0319166001600160a01b03909216918217905581529180529020829055505b602160008154612d2690613a38565b90915550506001600160a01b03166000908152602080805260408083208390556021548352601f909152902080546001600160a01b0319169055565b6021805460009182612d738361371b565b909155506000818152601f6020908152604080832080546001600160a01b039097166001600160a01b0319909716871790559482528052929092209190915550565b606081836020015183604051602001612dd093929190613a7e565b604051602081830303815290604052905092915050565b606081600001518260200151604051602001612e04929190613afd565b6040516020818303038152906040529050919050565b60405180610340016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b80356001600160a01b0381168114610e2757600080fd5b600060208284031215612f0657600080fd5b610ad382612edd565b600060208284031215612f2157600080fd5b5035919050565b60005b83811015612f43578181015183820152602001612f2b565b50506000910152565b60008151808452612f64816020860160208601612f28565b601f01601f19169290920160200192915050565b602081526000610ad36020830184612f4c565b60008060408385031215612f9e57600080fd5b612fa783612edd565b946020939093013593505050565b600080600060608486031215612fca57600080fd5b612fd384612edd565b9250612fe160208501612edd565b9150604084013590509250925092565b6000806040838503121561300457600080fd5b50508035926020909101359150565b60006040820184835260206040602085015281855180845260608601915060208701935060005b8181101561305f5784516001600160a01b03168352938301939183019160010161303a565b5090979650505050505050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e08082015190830152610100808201519083015261012080820151908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c080820151908301526101e08082015190830152610200808201519083015261022080820151908301526102408082015190830152610260808201519083015261028080820151908301526102a080820151908301526102c080820151908301526102e08082015190830152610300808201519083015261032090810151910152565b6103408101610a9e828461306c565b60006040828403121561319e57600080fd5b50919050565b6000806000606084860312156131b957600080fd5b6131c284612edd565b95602085013595506040909401359392505050565b60006040820184835260206040602085015281855180845260608601915060208701935060005b8181101561305f5761321183865161306c565b9383019361034092909201916001016131fe565b6000604080830185845260206040602086015281865180845260608701915060208801935060005b818110156132725784518051845284015184840152938301939185019160010161324d565b509098975050505050505050565b6000806040838503121561329357600080fd5b823591506132a360208401612edd565b90509250929050565b6000806000606084860312156132c157600080fd5b505081359360208301359350604090920135919050565b60006040820184835260206040602085015281855180845260608601915060608160051b87010193506020870160005b8281101561333657605f19888703018452613324868351612f4c565b95509284019290840190600101613308565b509398975050505050505050565b6000806040838503121561335757600080fd5b61336083612edd565b91506132a360208401612edd565b600181811c9082168061338257607f821691505b60208210810361319e57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610a9e57610a9e6133b8565b81810381811115610a9e57610a9e6133b8565b634e487b7160e01b600052603260045260246000fd5b604051610340810167ffffffffffffffff8111828210171561343c57634e487b7160e01b600052604160045260246000fd5b60405290565b6000610340828403121561345557600080fd5b61345d61340a565b825181526020808401519082015260408084015190820152606080840151908201526080808401519082015260a0808401519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e08084015190820152610200808401519082015261022080840151908201526102408084015190820152610260808401519082015261028080840151908201526102a080840151908201526102c080840151908201526102e080840151908201526103008084015190820152610320928301519281019290925250919050565b600181815b808511156135b1578160001904821115613597576135976133b8565b808516156135a457918102915b93841c939080029061357b565b509250929050565b6000826135c857506001610a9e565b816135d557506000610a9e565b81600181146135eb57600281146135f557613611565b6001915050610a9e565b60ff841115613606576136066133b8565b50506001821b610a9e565b5060208310610133831016604e8410600b8410161715613634575081810a610a9e565b61363e8383613576565b8060001904821115613652576136526133b8565b029392505050565b6000610ad360ff8416836135b9565b8082028115828204841417610a9e57610a9e6133b8565b634e487b7160e01b600052601260045260246000fd5b6000826136a5576136a5613680565b500490565b6000604082840312156136bc57600080fd5b6040516040810181811067ffffffffffffffff821117156136ed57634e487b7160e01b600052604160045260246000fd5b604052823581526020928301359281019290925250919050565b60008261371657613716613680565b500690565b60006001820161372d5761372d6133b8565b5060010190565b7f3c73766720786d6c6e733d27687474703a2f2f7777772e77332e6f72672f3230815273030302f737667272076696577426f783d273020360641b60208201526000600160fd1b8060348401528451613794816035860160208901612f28565b8084019050816035820152845191506137b4826036830160208801612f28565b61139f60f11b91016036810191909152603801949350505050565b703c7265637420783d27302720793d27302760781b8152672077696474683d2760c01b601182015260008451602061380e826019860160208a01612f28565b6927206865696768743d2760b01b6019928501928301528551613838816023850160208a01612f28565b67272066696c6c3d2760c01b602393909101928301528454602b90600090600181811c908083168061386b57607f831692505b60208310810361388957634e487b7160e01b85526022600452602485fd5b80801561389d57600181146138b8576138ea565b60ff198516602b8a0152602b84151585028a010195506138ea565b60008c81526020902060005b858110156138df5781548b82018a01529084019089016138c4565b5050602b848a010195505b5050505050613902816213979f60e91b815260030190565b9998505050505050505050565b6000885160206139228285838e01612f28565b8951918401916139358184848e01612f28565b89519201916139478184848d01612f28565b88519201916139598184848c01612f28565b875192019161396b8184848b01612f28565b865192019161397d8184848a01612f28565b855192019161398f8184848901612f28565b919091019a9950505050505050505050565b600085516139b3818460208a01612f28565b8551908301906139c7818360208a01612f28565b85519101906139da818360208901612f28565b84519101906139ed818360208801612f28565b019695505050505050565b60008351613a0a818460208801612f28565b835190830190613a1e818360208801612f28565b651e17b9bb339f60d11b9101908152600601949350505050565b600081613a4757613a476133b8565b506000190190565b60008351613a61818460208801612f28565b835190830190613a75818360208801612f28565b01949350505050565b6b3c706174682066696c6c3d2760a01b815260008451613aa581600c850160208901612f28565b642720643d2760d81b600c918401918201528451613aca816011840160208901612f28565b8451910190613ae0816011840160208801612f28565b6213979f60e91b6011929091019182015260140195945050505050565b6b3c706174682066696c6c3d2760a01b815260008351613b2481600c850160208801612f28565b642720643d2760d81b600c918401918201528351613b49816011840160208801612f28565b6213979f60e91b6011929091019182015260140194935050505056fea2646970667358221220bcb9d4758b5e45c10563cc603e122f7ca83c44c53d7dd9fe0072865859ab26fe64736f6c63430008190033

Deployed Bytecode

0x6080604052600436106102765760003560e01c806374ae51361161014f578063b42781ee116100c1578063dd0b281e1161007a578063dd0b281e14610886578063dd62ed3e146108a6578063dde415fa14610733578063e7a966b6146108ec578063f2fde38b1461090c578063f578990e1461092c57600080fd5b8063b42781ee146107c2578063b42dfa0d146107e2578063b4377a3e146107f8578063b4f243a414610818578063c01e21af14610838578063d5a426061461085857600080fd5b80638da5cb5b116101135780638da5cb5b1461070b5780638fdada4a1461073357806395d89b411461074957806398bafaa31461075e578063a9059cbb1461078c578063af504def146107ac57600080fd5b806374ae51361461065d578063750e8d101461067d5780637673bfa4146106ab5780637c3b3b87146106cb57806387cd1555146106eb57600080fd5b80633860a393116101e85780635534b159116101ac5780635534b159146105695780635e927ceb146105895780636a29f5e5146105a957806370a08231146105fd57806370db69d614610633578063715018a61461064857600080fd5b80633860a393146104ae5780633fc0fdcb146104dc578063422b9e231461050957806353388fd514610529578063544736e61461054957600080fd5b80630dfa2c481161023a5780630dfa2c481461040857806318160ddd1461042857806323b872dd1461043d5780632547b84d1461045d5780632d12d34b1461047d578063313ce5671461049257600080fd5b8063018a3741146103405780630568e65e1461036957806306a86dd71461039657806306fdde03146103c3578063095ea7b3146103d857600080fd5b3661033b5760007f000000000000000000000000f28e01b27a84bd2393b9adb28565abfa32af79f26001600160a01b03163460405160006040518083038185875af1925050503d80600081146102e8576040519150601f19603f3d011682016040523d82523d6000602084013e6102ed565b606091505b505080915050806103395760405162461bcd60e51b815260206004820152601160248201527031b0b7103737ba1033b2ba1032ba3432b960791b60448201526064015b60405180910390fd5b005b600080fd5b34801561034c57600080fd5b5061035660215481565b6040519081526020015b60405180910390f35b34801561037557600080fd5b50610356610384366004612ef4565b60246020526000908152604090205481565b3480156103a257600080fd5b506103b66103b1366004612f0f565b61094c565b6040516103609190612f78565b3480156103cf57600080fd5b506103b66109f8565b3480156103e457600080fd5b506103f86103f3366004612f8b565b610a8a565b6040519015158152602001610360565b34801561041457600080fd5b506103b6610423366004612f0f565b610aa4565b34801561043457600080fd5b50600254610356565b34801561044957600080fd5b506103f8610458366004612fb5565b610ab4565b34801561046957600080fd5b506103b6610478366004612f0f565b610ada565b34801561048957600080fd5b50610356600181565b34801561049e57600080fd5b5060405160098152602001610360565b3480156104ba57600080fd5b506104ce6104c9366004612ff1565b610aea565b604051610360929190613013565b3480156104e857600080fd5b506104fc6104f7366004612f8b565b610bf2565b604051610360919061317d565b34801561051557600080fd5b506103b661052436600461318c565b610c8a565b34801561053557600080fd5b506103b6610544366004612f0f565b610d02565b34801561055557600080fd5b50601c546001600160a01b031615156103f8565b34801561057557600080fd5b506103b6610584366004612f0f565b610d12565b34801561059557600080fd5b506103396105a4366004612f0f565b610d22565b3480156105b557600080fd5b506105e86105c4366004612f8b565b60236020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610360565b34801561060957600080fd5b50610356610618366004612ef4565b6001600160a01b031660009081526020819052604090205490565b34801561063f57600080fd5b50610356610d2f565b34801561065457600080fd5b50610339610e2c565b34801561066957600080fd5b506103b6610678366004612f0f565b610e40565b34801561068957600080fd5b5061069d6106983660046131a4565b610e50565b6040516103609291906131d7565b3480156106b757600080fd5b506103b66106c6366004612f0f565b61100c565b3480156106d757600080fd5b506104fc6106e636600461318c565b61101c565b3480156106f757600080fd5b506103b6610706366004612f0f565b6112e0565b34801561071757600080fd5b506005546040516001600160a01b039091168152602001610360565b34801561073f57600080fd5b506103566103e881565b34801561075557600080fd5b506103b66112f0565b34801561076a57600080fd5b5061077e6107793660046131a4565b6112ff565b604051610360929190613225565b34801561079857600080fd5b506103f86107a7366004612f8b565b61146f565b3480156107b857600080fd5b5061035660255481565b3480156107ce57600080fd5b506103396107dd366004612f0f565b61147d565b3480156107ee57600080fd5b5061035660225481565b34801561080457600080fd5b50610339610813366004613280565b61148a565b34801561082457600080fd5b506103b6610833366004612f8b565b6114e9565b34801561084457600080fd5b506103566108533660046132ac565b611523565b34801561086457600080fd5b506108786108733660046131a4565b6115bb565b6040516103609291906132d8565b34801561089257600080fd5b506103396108a1366004612ef4565b611729565b3480156108b257600080fd5b506103566108c1366004613344565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3480156108f857600080fd5b506103b6610907366004612f0f565b611757565b34801561091857600080fd5b50610339610927366004612ef4565b611767565b34801561093857600080fd5b506103b6610947366004612f0f565b6117a5565b6007818154811061095c57600080fd5b9060005260206000200160009150905080546109779061336e565b80601f01602080910402602001604051908101604052809291908181526020018280546109a39061336e565b80156109f05780601f106109c5576101008083540402835291602001916109f0565b820191906000526020600020905b8154815290600101906020018083116109d357829003601f168201915b505050505081565b606060038054610a079061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054610a339061336e565b8015610a805780601f10610a5557610100808354040283529160200191610a80565b820191906000526020600020905b815481529060010190602001808311610a6357829003601f168201915b5050505050905090565b600033610a988185856117b5565b60019150505b92915050565b6009818154811061095c57600080fd5b600033610ac28582856117c7565b610acd858585611845565b60019150505b9392505050565b600d818154811061095c57600080fd5b600060606021548410610b0e57505060408051600080825260208201909252610beb565b6000610b1a84866133ce565b9050602154811115610b2b57506021545b610b3585826133e1565b92508267ffffffffffffffff811115610b5057610b506133a2565b604051908082528060200260200182016040528015610b79578160200160208202803683370190505b509150845b83811015610be857601f6000610b9483896133ce565b815260200190815260200160002060009054906101000a90046001600160a01b0316838281518110610bc857610bc86133f4565b6001600160a01b0390921660209283029190910190910152600101610b7e565b50505b9250929050565b610bfa612e1a565b6001600160a01b0383166000908152602360209081526040808320858452909152908190209051637c3b3b8760e01b81528154600482015260019091015460248201523090637c3b3b879060440161034060405180830381865afa158015610c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad39190613442565b604051637c3b3b8760e01b81528135600482015260208201356024820152606090610a9e903090637c3b3b87906044015b61034060405180830381865afa158015610cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfd9190613442565b611997565b6008818154811061095c57600080fd5b600f818154811061095c57600080fd5b610d2a611b71565b601b55565b6000610d45601c546001600160a01b0316151590565b610d6657610d556009600a61365a565b610d61906103e8613669565b905090565b60006127106001601d5442610d7b91906133e1565b610d876009600a61365a565b610d93906103e8613669565b610d9d9190613669565b610da79190613669565b610db19190613696565b612710610dc06009600a61365a565b610dcc906103e8613669565b610dd7906005613669565b610de19190613696565b610deb91906133ce565b9050610df96009600a61365a565b610e05906103e8613669565b811115610e2757610e186009600a61365a565b610e24906103e8613669565b90505b919050565b610e34611b71565b610e3e6000611b9e565b565b600b818154811061095c57600080fd5b6001600160a01b038316600090815260246020526040812054606090808510610eaf576040805160008082526020820190925281610ea4565b610e91612e1a565b815260200190600190039081610e895790505b509250925050611004565b6000610ebb85876133ce565b905081811115610ec85750805b610ed286826133e1565b93508367ffffffffffffffff811115610eed57610eed6133a2565b604051908082528060200260200182016040528015610f2657816020015b610f13612e1a565b815260200190600190039081610f0b5790505b50925060005b84811015611000576001600160a01b03881660009081526023602052604081203091637c3b3b879190610f5f858c6133ce565b81526020019081526020016000206040518263ffffffff1660e01b8152600401610f99919081548152600190910154602082015260400190565b61034060405180830381865afa158015610fb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdb9190613442565b848281518110610fed57610fed6133f4565b6020908102919091010152600101610f2c565b5050505b935093915050565b6006818154811061095c57600080fd5b611024612e1a565b600060405180604001604052808480360381019061104291906136aa565b815260200160008152509050611056612e1a565b60065461106283611bf0565b61106c9190613707565b81526019546110869060ff1661108184611bf0565b611c46565b60208201526110ad600761109984611bf0565b8451602001516110a890611c5d565b611c7f565b6040820152601b546110c190600390613696565b6110ca83611c97565b1115611101576019546110e890610100900460ff1661108184611bf0565b60608201526110fb600d61109984611bf0565b60808201525b60195461111a9062010000900460ff1661108184611bf0565b60a082015260095461112b83611bf0565b6111359190613707565b60c0820152601b5461114990600390613696565b61115283611c97565b111561118c57601954611172906301000000900460ff1661108184611bf0565b60e0820152611185600a61109984611bf0565b6101008201525b6003601b5461119b9190613696565b6111a483611c97565b11156111e0576019546111c590640100000000900460ff1661108184611bf0565b6101a08201526111d9600861109984611bf0565b6101c08201525b6111ee600e61109984611bf0565b6101e0820152601954611211906601000000000000900460ff1661108184611bf0565b610200820152611225600b61109984611bf0565b610220820152601b5461123a90600390613696565b61124383611c97565b11156112825760195461126790670100000000000000900460ff1661108184611bf0565b61028082015261127b600f61109984611bf0565b6102a08201525b6003601b546112919190613696565b61129a83611c97565b1115610ad3576019546112bf9068010000000000000000900460ff1661108184611bf0565b6102c08201526112d3600c61109984611bf0565b6102e08201529392505050565b600e818154811061095c57600080fd5b606060048054610a079061336e565b6001600160a01b038316600090815260246020526040812054606090808510611369576040805160008082526020820190925281610ea4565b6040805180820190915260008082526020820152815260200190600190039081611338579050509250925050611004565b600061137585876133ce565b9050818111156113825750805b61138c86826133e1565b93508367ffffffffffffffff8111156113a7576113a76133a2565b6040519080825280602002602001820160405280156113ec57816020015b60408051808201909152600080825260208201528152602001906001900390816113c55790505b50925060005b84811015611000576001600160a01b03881660009081526023602052604081209061141d838a6133ce565b81526020019081526020016000206040518060400160405290816000820154815260200160018201548152505084828151811061145c5761145c6133f4565b60209081029190910101526001016113f2565b600033610a98818585611845565b611485611b71565b601a55565b3360009081526024602052604090205482106114da5760405162461bcd60e51b815260206004820152600f60248201526e0d2dcc6dee4e4cac6e840d2dcc8caf608b1b6044820152606401610330565b6114e5338383611cb3565b5050565b604051633fc0fdcb60e01b81526001600160a01b038316600482015260248101829052606090610ad3903090633fc0fdcb90604401610cbb565b600080805b85811015611559578361153b8183613669565b61154591906133ce565b61154f90836133ce565b9150600101611528565b6115638286613707565b945060009150600090505b858110156115af57836115818183613669565b61158b91906133ce565b61159590836133ce565b91508482106115a7579150610ad39050565b60010161156e565b50600095945050505050565b6001600160a01b038316600090815260246020526040812054606090808510611613576040805160008082526020820190925281610ea4565b60608152602001906001900390816115f4579050509250925050611004565b600061161f85876133ce565b90508181111561163857508061163581876133e1565b93505b8367ffffffffffffffff811115611651576116516133a2565b60405190808252806020026020018201604052801561168457816020015b606081526020019060019003908161166f5790505b5092508560005b8282101561171d576001600160a01b0389166000908152602360209081526040808320858452909152908190209051637c3b3b8760e01b81528154600482015260019091015460248201526116ea903090637c3b3b8790604401610cbb565b85826116f58161371b565b935081518110611707576117076133f4565b602002602001018190525081600101915061168b565b50505050935093915050565b611731611b71565b601c80546001600160a01b0319166001600160a01b039290921691909117905542601d55565b600c818154811061095c57600080fd5b61176f611b71565b6001600160a01b03811661179957604051631e4fbdf760e01b815260006004820152602401610330565b6117a281611b9e565b50565b600a818154811061095c57600080fd5b6117c28383836001611d15565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461183f578181101561183057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610330565b61183f84848484036000611d15565b50505050565b6001600160a01b038216158061186557506001600160a01b03821661dead145b15611875576117c2838383611dea565b601c546001600160a01b031615801561191f57506001600160a01b03831615806118a757506001600160a01b03831630145b806118e357507f000000000000000000000000f28e01b27a84bd2393b9adb28565abfa32af79f26001600160a01b0316836001600160a01b0316145b8061191f57507f000000000000000000000000f28e01b27a84bd2393b9adb28565abfa32af79f26001600160a01b0316826001600160a01b0316145b1561192f576117c283838361202e565b601c54600160a01b900460ff161561194c576117c283838361202e565b601c546001600160a01b039081169084160361196c576117c2828261208d565b601c546001600160a01b039081169083160361198c576117c28382612160565b6117c2838383611dea565b606060006119a5600a61227d565b6119af600a61227d565b6040516020016119c0929190613734565b60408051601f1981840301815291905290506000816119df600a61227d565b6119e9600a61227d565b6006876000015181548110611a0057611a006133f4565b90600052602060002001604051602001611a1c939291906137cf565b604051602081830303815290604052611a41601060078860200151896040015161237e565b611a57601260098960a001518a60c0015161237e565b611a6d6011600d8a606001518b6080015161237e565b611a846013600a8b60e001518c610100015161237e565b611a9c601460088c6101a001518d6101c0015161237e565b604051602001611ab2979695949392919061390f565b60405160208183030381529060405290506000611ad96015600e6001886101e0015161237e565b611af16016600b88610200015189610220015161237e565b611b096017600f8961028001518a6102a0015161237e565b611b216018600c8a6102c001518b6102e0015161247a565b604051602001611b3494939291906139a1565b60405160208183030381529060405290508181604051602001611b589291906139f8565b6040516020818303038152906040529350505050919050565b6005546001600160a01b03163314610e3e5760405163118cdaa760e01b8152336004820152602401610330565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80518051602091820151918301805160009391611c0c8261371b565b9052604080516020810194909452830191909152606082015260800160408051601f19818403018152919052805160209091012092915050565b6000611c528383613707565b610ad39060016133ce565b6000601a54821015611c775781601a54610a9e91906133e1565b506001919050565b8254600090611c8f908484611523565b949350505050565b805160200151600090611ca983611bf0565b610a9e9190613707565b6001600160a01b03831660009081526023602090815260408083208584528252918290208251808401909352805483526001015490820152611d018483611cfc6009600a61365a565b6124cc565b611d0b8484612530565b61183f828261263a565b6001600160a01b038416611d3f5760405163e602df0560e01b815260006004820152602401610330565b6001600160a01b038316611d6957604051634a1406b160e11b815260006004820152602401610330565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561183f57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051611ddc91815260200190565b60405180910390a350505050565b611df26126ff565b6001600160a01b03831660009081526020819052604081205490611e1683836133e1565b90506000611e39856001600160a01b031660009081526020819052604090205490565b90506000611e4785836133ce565b90506001600160a01b0386161580611e6957506001600160a01b03861661dead145b15611e75575060009050805b6000611e836009600a61365a565b611e8d9085613696565b611e996009600a61365a565b611ea39087613696565b611ead91906133e1565b90506000611ebd6009600a61365a565b611ec79085613696565b611ed36009600a61365a565b611edd9085613696565b611ee791906133e1565b90508181811115611ef55750805b6001600160a01b038a166000908152602460205260408120545b82821015611f87578015611f87576000611f2882613a38565b6001600160a01b038e1660009081526023602090815260408083208484528252918290208251808401909352805483526001015490820152909250829150611f708e83612530565b611f7a8d8261263a565b5050816001019150611f0f565b82915b85831015611fb8576000611f9d83613a38565b9250829050611fac8e82612530565b50826001019250611f8a565b8092505b8483101561200f5760006040518060400160405280602660008154611fe09061371b565b91829055508152602001611ff56103e8612729565b905290506120038d8261263a565b50826001019250611fbc565b61201a8d8d8d6124cc565b505050505050505050506117c26001601e55565b6001600160a01b03831661205857604051634b637e8f60e11b815260006004820152602401610330565b6001600160a01b0382166120825760405163ec442f0560e01b815260006004820152602401610330565b6117c2838383612778565b6120956126ff565b6001600160a01b038216600090815260208190526040812054906120b983836133ce565b905060006120c96009600a61365a565b6120d39084613696565b6120df6009600a61365a565b6120e99084613696565b6120f391906133e1565b905060005b81811015612148576000604051806040016040528060266000815461211c9061371b565b918290555081526020016121316103e8612729565b9052905061213f878261263a565b506001016120f8565b61215286866128a2565b505050506114e56001601e55565b601c805460ff60a01b1916600160a01b17905561217b6126ff565b6001600160a01b0382166000908152602081905260408120549061219f83836133e1565b905060006121af6009600a61365a565b6121b99083613696565b6121c56009600a61365a565b6121cf9085613696565b6121d991906133e1565b6001600160a01b038616600090815260246020526040812054919250905b82821015612245576103e8602254101561221f5760226000815461221a9061371b565b909155505b801561223a5761223a8761223283613a38565b925082612530565b8160010191506121f7565b601c5461225d9088906001600160a01b031688611845565b505050505061226c6001601e55565b5050601c805460ff60a01b19169055565b6060816000036122a45750506040805180820190915260018152600360fc1b602082015290565b8160005b81156122ce57806122b88161371b565b91506122c79050600a83613696565b91506122a8565b60008167ffffffffffffffff8111156122e9576122e96133a2565b6040519080825280601f01601f191660200182016040528015612313576020820181803683370190505b5090505b8415611c8f576123286001836133e1565b9150612335600a86613707565b6123409060306133ce565b60f81b818381518110612355576123556133f4565b60200101906001600160f81b031916908160001a905350612377600a86613696565b9450612317565b60608260000361239d5750604080516020810190915260008152611c8f565b6124718483815481106123b2576123b26133f4565b9060005260206000200180546123c79061336e565b80601f01602080910402602001604051908101604052809291908181526020018280546123f39061336e565b80156124405780601f1061241557610100808354040283529160200191612440565b820191906000526020600020905b81548152906001019060200180831161242357829003601f168201915b505050505086600060018761245591906133e1565b815260200190815260200160002061290d90919063ffffffff16565b95945050505050565b6060826000036124995750604080516020810190915260008152611c8f565b8260010361239d576124c58560006124b26001876133e1565b8152602001908152602001600020612ab1565b9050611c8f565b601c805460ff60a01b1916600160a01b1790556001600160a01b03821615806124ff57506001600160a01b03821661dead145b156125135761250e8382612c4a565b61251e565b61251e83838361202e565b5050601c805460ff60a01b1916905550565b601c546001600160a01b039081169083160361254a575050565b6001600160a01b0382166000908152602460205260408120805490919061257090613a38565b91829055506000036125855761258582612c80565b60256000815461259490613a38565b909155506001600160a01b038216600090815260246020526040902054818114612608576001600160a01b0383166000908152602360209081526040808320848452808352818420825180840184528154815260019182015481860190815288875292909452919093209151825591519101555b6001600160a01b0390921660009081526023602090815260408083209483529390529182208281556001019190915550565b601c546001600160a01b0390811690831603612654575050565b6001600160a01b0382166000908152602460205260408120805490919061267a9061371b565b918290555060010361268f5761268f82612d62565b60256000815461269e9061371b565b909155506001600160a01b0382166000908152602460205260408120546126c7906001906133e1565b6001600160a01b0393909316600090815260236020908152604080832095835294815293902082518155919092015160019091015550565b6002601e540361272257604051633ee5aeb560e01b815260040160405180910390fd5b6002601e55565b60006103e86022548361273c9190613669565b6127469190613696565b91508160000361275557600191505b600160225411156127745760226000815461276f90613a38565b909155505b5090565b6001600160a01b0383166127a357806002600082825461279891906133ce565b909155506128159050565b6001600160a01b038316600090815260208190526040902054818110156127f65760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610330565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661283157600280548290039055612850565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161289591815260200190565b60405180910390a3505050565b806128ab610d2f565b8111156128e45760405162461bcd60e51b81526020600482015260076024820152666d61782062757960c81b6044820152606401610330565b601c805460ff60a01b198116600160a01b1790915561251e906001600160a01b0316848461202e565b60608060005b8454811015612aa95781612a7e85878481548110612933576129336133f4565b906000526020600020906002020160405180604001604052908160008201805461295c9061336e565b80601f01602080910402602001604051908101604052809291908181526020018280546129889061336e565b80156129d55780601f106129aa576101008083540402835291602001916129d5565b820191906000526020600020905b8154815290600101906020018083116129b857829003601f168201915b505050505081526020016001820180546129ee9061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054612a1a9061336e565b8015612a675780601f10612a3c57610100808354040283529160200191612a67565b820191906000526020600020905b815481529060010190602001808311612a4a57829003601f168201915b505050505081525050612db590919063ffffffff16565b604051602001612a8f929190613a4f565b60408051601f198184030181529190529150600101612913565b509392505050565b60608060005b8354811015612c435781612c18858381548110612ad657612ad66133f4565b9060005260206000209060020201604051806040016040529081600082018054612aff9061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054612b2b9061336e565b8015612b785780601f10612b4d57610100808354040283529160200191612b78565b820191906000526020600020905b815481529060010190602001808311612b5b57829003601f168201915b50505050508152602001600182018054612b919061336e565b80601f0160208091040260200160405190810160405280929190818152602001828054612bbd9061336e565b8015612c0a5780601f10612bdf57610100808354040283529160200191612c0a565b820191906000526020600020905b815481529060010190602001808311612bed57829003601f168201915b505050505081525050612de7565b604051602001612c29929190613a4f565b60408051601f198184030181529190529150600101612ab7565b5092915050565b6001600160a01b038216612c7457604051634b637e8f60e11b815260006004820152602401610330565b6114e582600083612778565b602154600003612c8d5750565b6001600160a01b0381166000908152602080526040902054602154612cb4906001906133e1565b8114612d17576000601f60006001602154612ccf91906133e1565b81526020808201929092526040908101600090812054858252601f845282822080546001600160a01b0319166001600160a01b03909216918217905581529180529020829055505b602160008154612d2690613a38565b90915550506001600160a01b03166000908152602080805260408083208390556021548352601f909152902080546001600160a01b0319169055565b6021805460009182612d738361371b565b909155506000818152601f6020908152604080832080546001600160a01b039097166001600160a01b0319909716871790559482528052929092209190915550565b606081836020015183604051602001612dd093929190613a7e565b604051602081830303815290604052905092915050565b606081600001518260200151604051602001612e04929190613afd565b6040516020818303038152906040529050919050565b60405180610340016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b80356001600160a01b0381168114610e2757600080fd5b600060208284031215612f0657600080fd5b610ad382612edd565b600060208284031215612f2157600080fd5b5035919050565b60005b83811015612f43578181015183820152602001612f2b565b50506000910152565b60008151808452612f64816020860160208601612f28565b601f01601f19169290920160200192915050565b602081526000610ad36020830184612f4c565b60008060408385031215612f9e57600080fd5b612fa783612edd565b946020939093013593505050565b600080600060608486031215612fca57600080fd5b612fd384612edd565b9250612fe160208501612edd565b9150604084013590509250925092565b6000806040838503121561300457600080fd5b50508035926020909101359150565b60006040820184835260206040602085015281855180845260608601915060208701935060005b8181101561305f5784516001600160a01b03168352938301939183019160010161303a565b5090979650505050505050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e08082015190830152610100808201519083015261012080820151908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c080820151908301526101e08082015190830152610200808201519083015261022080820151908301526102408082015190830152610260808201519083015261028080820151908301526102a080820151908301526102c080820151908301526102e08082015190830152610300808201519083015261032090810151910152565b6103408101610a9e828461306c565b60006040828403121561319e57600080fd5b50919050565b6000806000606084860312156131b957600080fd5b6131c284612edd565b95602085013595506040909401359392505050565b60006040820184835260206040602085015281855180845260608601915060208701935060005b8181101561305f5761321183865161306c565b9383019361034092909201916001016131fe565b6000604080830185845260206040602086015281865180845260608701915060208801935060005b818110156132725784518051845284015184840152938301939185019160010161324d565b509098975050505050505050565b6000806040838503121561329357600080fd5b823591506132a360208401612edd565b90509250929050565b6000806000606084860312156132c157600080fd5b505081359360208301359350604090920135919050565b60006040820184835260206040602085015281855180845260608601915060608160051b87010193506020870160005b8281101561333657605f19888703018452613324868351612f4c565b95509284019290840190600101613308565b509398975050505050505050565b6000806040838503121561335757600080fd5b61336083612edd565b91506132a360208401612edd565b600181811c9082168061338257607f821691505b60208210810361319e57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610a9e57610a9e6133b8565b81810381811115610a9e57610a9e6133b8565b634e487b7160e01b600052603260045260246000fd5b604051610340810167ffffffffffffffff8111828210171561343c57634e487b7160e01b600052604160045260246000fd5b60405290565b6000610340828403121561345557600080fd5b61345d61340a565b825181526020808401519082015260408084015190820152606080840151908201526080808401519082015260a0808401519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e08084015190820152610200808401519082015261022080840151908201526102408084015190820152610260808401519082015261028080840151908201526102a080840151908201526102c080840151908201526102e080840151908201526103008084015190820152610320928301519281019290925250919050565b600181815b808511156135b1578160001904821115613597576135976133b8565b808516156135a457918102915b93841c939080029061357b565b509250929050565b6000826135c857506001610a9e565b816135d557506000610a9e565b81600181146135eb57600281146135f557613611565b6001915050610a9e565b60ff841115613606576136066133b8565b50506001821b610a9e565b5060208310610133831016604e8410600b8410161715613634575081810a610a9e565b61363e8383613576565b8060001904821115613652576136526133b8565b029392505050565b6000610ad360ff8416836135b9565b8082028115828204841417610a9e57610a9e6133b8565b634e487b7160e01b600052601260045260246000fd5b6000826136a5576136a5613680565b500490565b6000604082840312156136bc57600080fd5b6040516040810181811067ffffffffffffffff821117156136ed57634e487b7160e01b600052604160045260246000fd5b604052823581526020928301359281019290925250919050565b60008261371657613716613680565b500690565b60006001820161372d5761372d6133b8565b5060010190565b7f3c73766720786d6c6e733d27687474703a2f2f7777772e77332e6f72672f3230815273030302f737667272076696577426f783d273020360641b60208201526000600160fd1b8060348401528451613794816035860160208901612f28565b8084019050816035820152845191506137b4826036830160208801612f28565b61139f60f11b91016036810191909152603801949350505050565b703c7265637420783d27302720793d27302760781b8152672077696474683d2760c01b601182015260008451602061380e826019860160208a01612f28565b6927206865696768743d2760b01b6019928501928301528551613838816023850160208a01612f28565b67272066696c6c3d2760c01b602393909101928301528454602b90600090600181811c908083168061386b57607f831692505b60208310810361388957634e487b7160e01b85526022600452602485fd5b80801561389d57600181146138b8576138ea565b60ff198516602b8a0152602b84151585028a010195506138ea565b60008c81526020902060005b858110156138df5781548b82018a01529084019089016138c4565b5050602b848a010195505b5050505050613902816213979f60e91b815260030190565b9998505050505050505050565b6000885160206139228285838e01612f28565b8951918401916139358184848e01612f28565b89519201916139478184848d01612f28565b88519201916139598184848c01612f28565b875192019161396b8184848b01612f28565b865192019161397d8184848a01612f28565b855192019161398f8184848901612f28565b919091019a9950505050505050505050565b600085516139b3818460208a01612f28565b8551908301906139c7818360208a01612f28565b85519101906139da818360208901612f28565b84519101906139ed818360208801612f28565b019695505050505050565b60008351613a0a818460208801612f28565b835190830190613a1e818360208801612f28565b651e17b9bb339f60d11b9101908152600601949350505050565b600081613a4757613a476133b8565b506000190190565b60008351613a61818460208801612f28565b835190830190613a75818360208801612f28565b01949350505050565b6b3c706174682066696c6c3d2760a01b815260008451613aa581600c850160208901612f28565b642720643d2760d81b600c918401918201528451613aca816011840160208901612f28565b8451910190613ae0816011840160208801612f28565b6213979f60e91b6011929091019182015260140195945050505050565b6b3c706174682066696c6c3d2760a01b815260008351613b2481600c850160208801612f28565b642720643d2760d81b600c918401918201528351613b49816011840160208801612f28565b6213979f60e91b6011929091019182015260140194935050505056fea2646970667358221220bcb9d4758b5e45c10563cc603e122f7ca83c44c53d7dd9fe0072865859ab26fe64736f6c63430008190033

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.