ETH Price: $3,553.92 (-0.23%)
Gas: 3 Gwei

Contract

0x32f8EE2B5707138e1bdd04D3631A04EB104dc141
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Set Approval For...200721422024-06-12 0:22:594 days ago1718151779IN
Fake_Phishing285157
0 ETH0.000184047.61855508
Set Approval For...200333622024-06-06 14:24:239 days ago1717683863IN
Fake_Phishing285157
0 ETH0.0006504826.92610054
Set Approval For...198839172024-05-16 17:05:5930 days ago1715879159IN
Fake_Phishing285157
0 ETH0.000214688.20347736
Set Approval For...198839172024-05-16 17:05:5930 days ago1715879159IN
Fake_Phishing285157
0 ETH0.000377938.20347736
Claim197787952024-05-02 0:13:5945 days ago1714608839IN
Fake_Phishing285157
0 ETH0.000706914.56205824
Set Approval For...196931742024-04-20 0:53:1157 days ago1713574391IN
Fake_Phishing285157
0 ETH0.000155336.42988088
Set Approval For...196525682024-04-14 8:25:5963 days ago1713083159IN
Fake_Phishing285157
0 ETH0.0005928212.84443353
Set Approval For...196223182024-04-10 2:42:1167 days ago1712716931IN
Fake_Phishing285157
0 ETH0.0008166517.717207
Set Approval For...195993312024-04-06 21:22:3570 days ago1712438555IN
Fake_Phishing285157
0 ETH0.0003018712.4957146
Breed195571632024-03-31 23:34:3576 days ago1711928075IN
Fake_Phishing285157
0 ETH0.0016626420.2329267
Breed195571552024-03-31 23:32:5976 days ago1711927979IN
Fake_Phishing285157
0 ETH0.0017209120.94202165
Breed195571422024-03-31 23:30:2376 days ago1711927823IN
Fake_Phishing285157
0 ETH0.0016511320.09286633
Breed195570842024-03-31 23:18:4776 days ago1711927127IN
Fake_Phishing285157
0 ETH0.0016427519.9934097
Breed195570722024-03-31 23:16:2376 days ago1711926983IN
Fake_Phishing285157
0 ETH0.0015713719.12458646
Breed195570562024-03-31 23:13:1176 days ago1711926791IN
Fake_Phishing285157
0 ETH0.0015744319.1619114
Breed195570512024-03-31 23:12:1176 days ago1711926731IN
Fake_Phishing285157
0 ETH0.0016009419.48452929
Unstake195570442024-03-31 23:10:4776 days ago1711926647IN
Fake_Phishing285157
0 ETH0.0033801521.76575182
Claim195570222024-03-31 23:06:2376 days ago1711926383IN
Fake_Phishing285157
0 ETH0.0014139318.1022445
Set Approval For...194720392024-03-19 23:24:3588 days ago1710890675IN
Fake_Phishing285157
0 ETH0.0009686340.09594614
Set Approval For...193076122024-02-25 22:35:47111 days ago1708900547IN
Fake_Phishing285157
0 ETH0.0007625331.56459205
Set Approval For...192822232024-02-22 9:19:23115 days ago1708593563IN
Fake_Phishing285157
0 ETH0.0007003928.99232747
Set Approval For...192701532024-02-20 16:38:59116 days ago1708447139IN
Fake_Phishing285157
0 ETH0.0009164537.9358444
Stake190994182024-01-27 17:30:47140 days ago1706376647IN
Fake_Phishing285157
0 ETH0.0010945514.15838443
Set Approval For...190934352024-01-26 21:24:35141 days ago1706304275IN
Fake_Phishing285157
0 ETH0.0006670714.47965459
Set Approval For...190508992024-01-20 21:56:47147 days ago1705787807IN
Fake_Phishing285157
0 ETH0.0003490814.45015388
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AlphaDogs

Compiler Version
v0.8.14+commit.80d49f37

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 15 : AlphaDogs.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

import {Ownable} from "@openzeppelin/access/Ownable.sol";
import {Strings} from "@openzeppelin/utils/Strings.sol";
import {MerkleProof} from "@openzeppelin/utils/cryptography/MerkleProof.sol";
import {ReentrancyGuard} from "@solmate/utils/ReentrancyGuard.sol";

import {IAlphaToken} from "$/interfaces/IAlphaToken.sol";
import {IAlphaDogs} from "$/interfaces/IAlphaDogs.sol";
import {IAlphaDogsAttributes} from "$/interfaces/IAlphaDogsAttributes.sol";

import {Genetics} from "$/libraries/Genetics.sol";
import {Gene} from "$/libraries/Gene.sol";
import {ERC721} from "$/ERC721.sol";

/// @title  AlphaDogs
/// @author Aleph Retamal <github.com/alephao>, Gustavo Tiago <github.com/gutiago>
contract AlphaDogs is IAlphaDogs, ERC721, Ownable, ReentrancyGuard {
    using Gene for uint256;
    using Strings for uint160;
    // ========================================
    // Immutable
    // ========================================

    address private constant BLACKHOLE = address(0);

    /// @notice amount of $ALPHA a staked genesis dog earn per day
    uint256 public constant GENESIS_TOKEN_PER_DAY = 10 ether;

    /// @notice amount of $ALPHA a staked puppy dog earn per day
    uint256 public constant PUPPY_TOKEN_PER_DAY = 2.5 ether;

    /// @notice price in $ALPHA to breed
    uint256 public constant BREEDING_PRICE = 600 ether;

    /// @notice price in $ALPHA to update name or lore of a dog
    uint256 public constant UPDATE_PRICE = 100 ether;

    /// @notice max amount of genesis tokens
    uint32 public immutable maxGenesis;

    /// @notice max amount of puppy tokens
    uint32 public immutable maxPuppies;

    /// @notice address of the $ALPHA ERC20
    IAlphaToken public immutable alphaToken;

    /// @notice merkle tree root for allow-list
    bytes32 public immutable merkleRoot;

    /// @notice number of reserved genesis tokens for wallets in the allow-list
    uint32 public immutable maxReserved;

    // ========================================
    // Mutable
    // ========================================

    /// @notice if the mint function is open
    bool public isSaleActive = false;

    /// @notice if supply should be reserved for allow-list
    bool public isSupplyReserved = true;

    /// @notice amount of genesis minted so far not via allow-list
    uint32 public genesisNonReservedSupply = 0;

    /// @notice amount of genesis minted so far via allow-list
    uint32 public genesisReservedSupply = 0;

    /// @notice amount of puppied minted so far
    uint32 public puppySupply = 0;

    /// @notice map from dog id to custom Name and Lore
    mapping(uint256 => CustomMetadata) internal metadata;

    /// @notice map from dog id to its staked state
    mapping(uint256 => Stake) public getStake;

    /// @notice check if an address already minted
    mapping(address => bool) public didMint;

    /// @notice address of the AlphaDogsAttributes contract
    IAlphaDogsAttributes public attributes;

    // ========================================
    // Constructor
    // ========================================

    constructor(
        uint32 _maxGenesis,
        uint32 _maxPuppies,
        uint32 _maxReserved,
        IAlphaToken _alphaToken,
        IAlphaDogsAttributes _attributes,
        bytes32 _merkleRoot
    ) ERC721("AlphaDogs", "AD") {
        maxGenesis = _maxGenesis;
        maxPuppies = _maxPuppies;
        maxReserved = _maxReserved;
        alphaToken = _alphaToken;
        attributes = _attributes;
        merkleRoot = _merkleRoot;
    }

    // ========================================
    // Modifiers
    // ========================================

    modifier dogzOwner(uint256 id) {
        if (ownerOf[id] != msg.sender) revert InvalidTokenOwner();
        _;
    }

    modifier whenSaleIsActive() {
        if (!isSaleActive) revert NotActive();
        _;
    }

    // " and \ are not valid
    modifier isValidString(string calldata value) {
        bytes memory str = bytes(value);

        for (uint256 i; i < str.length; i++) {
            bytes1 char = str[i];
            if ((char == 0x22) || (char == 0x5c)) revert InvalidChar();
        }
        _;
    }

    // ========================================
    // Owner only
    // ========================================

    function setIsSaleActive(bool _isSaleActive) external onlyOwner {
        if (isSaleActive == _isSaleActive) revert NotChanged();
        isSaleActive = _isSaleActive;
    }

    function setIsSupplyReserved(bool _isSupplyReserved) external onlyOwner {
        if (isSupplyReserved == _isSupplyReserved) revert NotChanged();
        isSupplyReserved = _isSupplyReserved;
    }

    // ========================================
    // Change NFT Data
    // ========================================

    function setName(uint256 id, string calldata newName)
        external
        override
        dogzOwner(id)
        isValidString(newName)
    {
        bytes memory n = bytes(newName);

        if (n.length > 25) revert InvalidNameLength();
        if (keccak256(n) == keccak256(bytes(metadata[id].name)))
            revert InvalidSameValue();

        metadata[id].name = newName;
        alphaToken.burn(msg.sender, UPDATE_PRICE);
        emit NameChanged(id, newName);
    }

    function setLore(uint256 id, string calldata newLore)
        external
        override
        dogzOwner(id)
        isValidString(newLore)
    {
        bytes memory n = bytes(newLore);

        if (keccak256(n) == keccak256(bytes(metadata[id].lore)))
            revert InvalidSameValue();

        metadata[id].lore = newLore;
        alphaToken.burn(msg.sender, UPDATE_PRICE);
        emit LoreChanged(id, newLore);
    }

    // ========================================
    // Breeding
    // ========================================

    function breed(uint256 mom, uint256 dad)
        external
        override
        dogzOwner(mom)
        dogzOwner(dad)
    {
        if (genesisLeft() != 0) revert NotActive();

        uint256 mintIndex = puppySupply;
        if (mintIndex == maxPuppies) revert InsufficientTokensAvailable();
        if (Gene.isPuppy(mom) || Gene.isPuppy(dad))
            revert FusionWithPuppyForbidden();
        if (mom == dad) revert FusionWithSameParentsForbidden();

        unchecked {
            puppySupply++;
        }

        uint256 puppyId = _generatePuppyTokenIdWithNoCollision(
            mom,
            dad,
            random(mintIndex)
        );
        alphaToken.burn(msg.sender, BREEDING_PRICE);
        //slither-disable-next-line reentrancy-no-eth
        _mint(msg.sender, puppyId);

        emit Breeded(puppyId, mom, dad);
    }

    function _generatePuppyTokenIdWithNoCollision(
        uint256 mom,
        uint256 dad,
        uint256 seed
    ) internal view returns (uint256 tokenId) {
        tokenId = Genetics.uniformCrossOver(mom, dad, seed);
        uint256 i = 3;
        while (ownerOf[tokenId] != BLACKHOLE) {
            tokenId = Genetics.incrementByte(tokenId, i);
            unchecked {
                i++;
            }
        }
    }

    // ========================================
    // Stake / Unstake
    // ========================================

    function stake(uint256[] calldata tokenIds) external override {
        if (tokenIds.length == 0) revert InvalidInput();
        if (msg.sender == address(0)) revert InvalidSender();

        uint256 tokenId;
        for (uint256 i = 0; i < tokenIds.length; ) {
            tokenId = tokenIds[i];
            // No need to check ownership since transferFrom already checks that
            // and the caller of this function should be the token Owner
            getStake[tokenId] = Stake(msg.sender, uint96(block.timestamp));
            _transfer(msg.sender, address(this), tokenId);
            emit Staked(tokenId);

            unchecked {
                ++i;
            }
        }
    }

    function unstake(uint256[] calldata tokenIds) external override {
        _claim(tokenIds, true);
    }

    function claim(uint256[] calldata tokenIds) external override {
        _claim(tokenIds, false);
    }

    function _claim(uint256[] calldata tokenIds, bool shouldUnstake) internal {
        if (tokenIds.length == 0) revert InvalidInput();
        if (msg.sender == address(0)) revert InvalidSender();

        // total rewards amount to claim
        uint256 totalRewards;

        // loop variables

        // rewards for current genzee in the loop below
        uint256 rewards;

        // current genzeeid in the loop below
        uint256 tokenId;

        // staking information for the current genzee in the loop below
        Stake memory stakeInfo;

        for (uint256 i = 0; i < tokenIds.length; ) {
            tokenId = tokenIds[i];
            stakeInfo = getStake[tokenId];

            if (stakeInfo.owner != msg.sender) revert InvalidTokenOwner();

            uint256 tokensPerDay = tokenId.isPuppy()
                ? PUPPY_TOKEN_PER_DAY
                : GENESIS_TOKEN_PER_DAY;

            rewards = stakeInfo.stakedAt > 1
                ? ((tokensPerDay * (block.timestamp - stakeInfo.stakedAt)) /
                    1 days)
                : 0;
            totalRewards += rewards;

            if (shouldUnstake) {
                getStake[tokenId] = Stake(BLACKHOLE, 1);
                _transfer(address(this), msg.sender, tokenId);
                emit Unstaked(tokenId, rewards);
            } else {
                //slither-disable-next-line incorrect-equality
                if (rewards == 0) revert InvalidAmountToClaim();
                getStake[tokenId].stakedAt = uint96(block.timestamp);
                emit ClaimedTokens(tokenId, rewards);
            }

            unchecked {
                ++i;
            }
        }

        //slither-disable-next-line incorrect-equality
        if (totalRewards == 0) return;
        alphaToken.mint(msg.sender, totalRewards);
    }

    // ========================================
    // Mint
    // ========================================

    function _generateTokenIdWithNoCollision(uint256 seed)
        internal
        view
        returns (uint256 tokenId)
    {
        tokenId = Genetics.generateGenes(seed);
        uint256 i = 3;
        while (ownerOf[tokenId] != BLACKHOLE) {
            tokenId = Genetics.incrementByte(tokenId, i);
            unchecked {
                i++;
            }
        }
    }

    function premint(bytes32[] calldata proof) external whenSaleIsActive {
        uint256 reservedSupply = genesisReservedSupply;

        if (didMint[msg.sender]) revert TokenLimitReached();
        if (reservedSupply + 2 > maxReserved)
            revert InsufficientReservedTokensAvailable();
        if (reservedSupply + genesisNonReservedSupply + 2 > maxGenesis)
            revert InsufficientTokensAvailable();

        bytes32 leaf = keccak256(
            abi.encodePacked(uint160(msg.sender).toHexString(20))
        );
        bool isProofValid = MerkleProof.verify(proof, merkleRoot, leaf);
        if (!isProofValid) revert InvalidMerkleProof();

        didMint[msg.sender] = true;

        unchecked {
            uint256 mintIndex = genesisSupply();
            genesisReservedSupply += 2;
            _safeMint(
                msg.sender,
                _generateTokenIdWithNoCollision(random(mintIndex + 1))
            );
            _safeMint(
                msg.sender,
                _generateTokenIdWithNoCollision(random(mintIndex + 2))
            );
        }
    }

    function mint() external whenSaleIsActive {
        // Can only mint once per address
        if (didMint[msg.sender]) {
            revert TokenLimitReached();
        }

        uint256 reservedSupply = genesisReservedSupply;
        uint256 nonReservedSupply = genesisNonReservedSupply;

        if (reservedSupply + nonReservedSupply + 2 > maxGenesis)
            revert InsufficientTokensAvailable();

        // When minting, if isSupplyReserved is on, public minters won't be able
        // to mint the amount reserved for allow-listed wallets
        if (
            isSupplyReserved && nonReservedSupply + 2 > maxGenesis - maxReserved
        ) {
            revert InsufficientNonReservedTokensAvailable();
        }

        didMint[msg.sender] = true;

        unchecked {
            uint256 mintIndex = genesisSupply();
            genesisNonReservedSupply += 2;
            _safeMint(
                msg.sender,
                _generateTokenIdWithNoCollision(random(mintIndex + 1))
            );
            _safeMint(
                msg.sender,
                _generateTokenIdWithNoCollision(random(mintIndex + 2))
            );
        }
    }

    function random(uint256 nonce) internal view returns (uint256) {
        return
            uint256(
                keccak256(
                    abi.encodePacked(
                        tx.origin, // solhint-disable-line avoid-tx-origin
                        tx.gasprice,
                        nonce,
                        block.number,
                        block.timestamp
                    )
                )
            );
    }

    // ========================================
    // View
    // ========================================

    function genesisSupply() public view returns (uint32) {
        unchecked {
            return genesisReservedSupply + genesisNonReservedSupply;
        }
    }

    /// @notice amount of tokens left to be minted
    function genesisLeft() public view returns (uint32) {
        unchecked {
            return maxGenesis - genesisSupply();
        }
    }

    /// @notice amount do puppies left to be created
    function puppyTokensLeft() external view returns (uint32) {
        unchecked {
            return maxPuppies - puppySupply;
        }
    }

    /// @notice total supply of nfts
    function totalSupply() external view returns (uint32) {
        unchecked {
            return genesisSupply() + puppySupply;
        }
    }

    function getMetadata(uint256 id)
        external
        view
        override
        returns (CustomMetadata memory)
    {
        return metadata[id];
    }

    // ========================================
    // Overrides
    // ========================================

    function tokenURI(uint256 id)
        public
        view
        override(ERC721)
        returns (string memory)
    {
        if (ownerOf[id] == BLACKHOLE) revert InvalidTokenID();
        CustomMetadata memory md = metadata[id];
        return attributes.tokenURI(id, bytes(md.name), md.lore);
    }
}

File 2 of 15 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../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.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

File 3 of 15 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 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);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

File 4 of 15 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Trees proofs.
 *
 * The proofs can be generated using the JavaScript library
 * https://github.com/miguelmota/merkletreejs[merkletreejs].
 * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
 *
 * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = _efficientHash(computedHash, proofElement);
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = _efficientHash(proofElement, computedHash);
            }
        }
        return computedHash;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 5 of 15 : ReentrancyGuard.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

File 6 of 15 : IAlphaToken.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

interface IAlphaToken {
    /// @dev 0x36a1c33f
    error NotChanged();
    /// @dev 0x3d693ada
    error NotAllowed();

    function mint(address addr, uint256 amount) external;

    function burn(address from, uint256 amount) external;
}

File 7 of 15 : IAlphaDogs.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

import {IAlphaDogsEvents} from "./IAlphaDogsEvents.sol";
import {IAlphaDogsErrors} from "./IAlphaDogsErrors.sol";

interface IAlphaDogs is IAlphaDogsEvents, IAlphaDogsErrors {
    struct CustomMetadata {
        string name;
        string lore;
    }

    struct Stake {
        address owner;
        uint96 stakedAt;
    }

    // mapping(uint256 => CustomMetadata) getMetadata;
    function getMetadata(uint256 id)
        external
        view
        returns (CustomMetadata memory);

    function setName(uint256 id, string calldata newName) external;

    function setLore(uint256 id, string calldata newLore) external;

    function stake(uint256[] calldata tokenIds) external;

    function unstake(uint256[] calldata tokenIds) external;

    function claim(uint256[] calldata tokenIds) external;

    function premint(bytes32[] calldata proof) external;

    function mint() external;

    function breed(uint256 mom, uint256 dad) external;
}

File 8 of 15 : IAlphaDogsAttributes.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

interface IAlphaDogsAttributes {
    function tokenURI(
        uint256 id,
        bytes memory name,
        string memory lore
    ) external view returns (string memory);
}

File 9 of 15 : Genetics.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

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

/// @title  AlphaDogs Genetics Library
/// @author Aleph Retamal <github.com/alephao>, Gustavo Tiago <github.com/gutiago>
/// @notice Library containing functions for creating and manipulating genes.
///
/// ### Creating a new gene
///
/// • When creating a new gene, we get a pseudo-random seed derive other seeds for each trait
/// • We're using A.J. Walker Alias Algorithm to pick traits with pre-defined rarity table
///   these are the weird hard-coded arrays in the `seedTo{Trait}` functions
/// • Note: we use a pseudo-random seed, meaning that the result can be somewhat manipulated
///   by mad-scientists of the chain.
///
/// ### Breeding
///
/// • For breeding we use uniform cross-over algorithm which is commonly used
///   in genetic algorithms. We walk throught each chromossome, picking from either mom or dad.
library Genetics {
    /// @dev    Generate genes from a seed
    ///
    ///         • Start with                  0x0
    ///         • Add background chromossome  0x77 = 0x0 + 0x77
    ///         • Shift 1 byte to the left    0x7700 = 0x77 << 8
    ///         • Add fur chromossome         0x7766 = 0x7700 + 0x66
    ///         • Same for each chromossome
    function generateGenes(uint256 seed) internal pure returns (uint256 genes) {
        genes |= Chromossomes.seedToBackground(seed);
        genes <<= 8;

        genes |= Chromossomes.seedToFur(seed);
        genes <<= 8;

        genes |= Chromossomes.seedToNeck(seed);
        genes <<= 8;

        genes |= Chromossomes.seedToEyes(seed);
        genes <<= 8;

        genes |= Chromossomes.seedToHat(seed);
        genes <<= 8;

        genes |= Chromossomes.seedToMouth(seed);
        genes <<= 8;

        genes |= Chromossomes.seedToNosering(seed);
    }

    /// @dev Increments the gene i in n (big endian/from right to left)
    ///
    /// ### Examples
    ///
    /// • incrementByte(0x110000, 0) = 0x110001
    /// • incrementByte(0x110000, 1) = 0x110100
    /// • incrementByte(0x110000, 2) = 0x120000
    ///
    /// ### A more readable version of the code
    ///
    /// unchecked {
    ///   uint256 shift = (i % 7) * 8;
    ///   uint256 mask = 0xFF << shift;
    ///   uint256 trait = gene & mask;
    ///   uint256 traitRaw = trait >> shift;
    ///   uint256 newTrait = (traitRaw + 1) % [4, 28, 11, 70, 36, 10, 21][i];
    ///   uint256 tokenIdWithoutOldTrait = ~mask & gene;
    ///   uint256 newGene = tokenIdWithoutOldTrait | (newTrait << shift);
    /// }
    ///
    /// ### Step by step explanation
    ///
    /// Explaining this for devs that look into other contracts to learn stuff like myself
    ///
    /// ### Glossary
    /// • Every 2 positions in an hexadecimal representation of a number = 1 byte
    ///   E.g.: In 0x112233, 11 is a byte, 22 is another byte, 33 is another byte
    /// • Zeros on the left can be ignored so 0x00011 = 0x11, using them here to make
    ///   it easier to see the math
    /// • 1 byte = 8 bits, so 0x1 << 8 will move 1 byte to the left (2 positions) resulting in 0x100
    ///
    /// In this example we have 0x1111221111 and want to increment `22` to `23`
    ///
    /// 1. Create a mask to get only the 22
    ///
    /// 0x1111221111 (gene)
    /// AND
    /// 0x0000FF0000 (mask)
    /// =
    /// 0x0000220000 (result)
    ///
    /// 2. Shift the byte "22" to the least significant byte, so we can increment
    ///
    /// 0x220000 >> (8 * 2) = 0x22
    ///
    /// 3. Increment
    ///
    /// 0x22 + 1 = 0x23. We're also checking against the amount of variants a trait has, that's why
    /// we're doing (byte + 1) % [X, X, X][i]
    ///
    /// 4. Move the byte back to its original position
    ///
    /// 0x23 << (8 * 2) = 0x230000
    ///
    /// 5. Invert the original mask to get all original bytes except the position we're manipulating
    ///
    /// ~0x0000FF0000 = 0xFFFF00FFFF
    ///
    /// 0xFFFF00FFFF
    /// AND
    /// 0x1111221111
    /// =
    /// 0x1111001111
    ///
    /// 6. Put the incremented byte back in the original value
    ///
    /// 0x1111001111
    /// OR
    /// 0x0000230000
    /// =
    /// 0x1111231111
    function incrementByte(uint256 gene, uint256 i)
        internal
        pure
        returns (uint256)
    {
        unchecked {
            // Number of bytes to shift, should be between 0 and 7
            uint256 shift = (i % 7) * 8;

            // Create the mask to do all the stuff mentioned in natspec
            uint256 mask = 0xFF << shift;
            return
                (~mask & gene) |
                (((((gene & mask) >> shift) + 1) %
                    [4, 28, 11, 70, 36, 10, 21][i % 7]) << shift);
        }
    }

    /// @dev    Uniform cross-over two "uint7", returns a "uint8" because a child has an extra byte
    /// @param  mom genes from mom
    /// @param  dad genes from dad
    /// @param  seed the seed is used to pick chromossomes between dad and mom.
    ///
    /// @dev If a specific byte in the seed is even, picks mom, otherwise picks dad.
    ///
    /// ### Examples
    ///
    /// • uniformCrossOver(0x11111111111111, 0x22222222222222, 0x0) = 0x0111111111111111
    /// • uniformCrossOver(0x11111111111111, 0x22222222222222, 0x1) = 0x0111111111111122
    /// • uniformCrossOver(0x11111111111111, 0x22222222222222, 0x0101) = 0x0111111111112222
    /// • uniformCrossOver(0x11111111111111, 0x22222222222222, 0x010101) = 0x0111111111222222
    /// • uniformCrossOver(0x11111111111111, 0x22222222222222, 0x01000100010001) = 0x0122112211221122
    function uniformCrossOver(
        uint256 mom,
        uint256 dad,
        uint256 seed
    ) internal pure returns (uint256) {
        unchecked {
            uint256 child = 0x0100000000000000;
            for (uint256 i = 0; i < 7; i++) {
                // Choose mom or dad to pick the chromossome from
                // If the byte on seed is even, pick mom
                uint256 chromossome = ((seed >> (8 * i)) & 0xFF) % 2 == 0
                    ? mom
                    : dad;

                // Create a mask to pick only the current byte/chromossome
                // E.g.: 3rd byte = 0xFF0000
                uint256 mask = 0xFF << (8 * i);

                // Add byte/chromossome to the child
                child |= (chromossome & mask);
            }

            return child;
        }
    }
}

File 10 of 15 : Gene.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

/// @title  AlphaDogs Gene Library
/// @author Aleph Retamal <github.com/alephao>
/// @notice Library containing functions for querying info about a gene.
library Gene {
    /// @notice A gene is puppy if its 8th byte is greater than 0
    function isPuppy(uint256 gene) internal pure returns (bool) {
        return (gene & 0xFF00000000000000) > 0;
    }

    /// @notice Get a specific chromossome in a gene, first position is 0
    function getChromossome(uint256 gene, uint32 position)
        internal
        pure
        returns (uint256)
    {
        unchecked {
            uint32 shift = 8 * position;
            return (gene & (0xFF << shift)) >> shift;
        }
    }

    function getBackground(uint256 gene) internal pure returns (uint256) {
        return getChromossome(gene, 6);
    }

    function getFur(uint256 gene) internal pure returns (uint256) {
        return getChromossome(gene, 5);
    }

    function getNeck(uint256 gene) internal pure returns (uint256) {
        return getChromossome(gene, 4);
    }

    function getEyes(uint256 gene) internal pure returns (uint256) {
        return getChromossome(gene, 3);
    }

    function getHat(uint256 gene) internal pure returns (uint256) {
        return getChromossome(gene, 2);
    }

    function getMouth(uint256 gene) internal pure returns (uint256) {
        return getChromossome(gene, 1);
    }

    function getNosering(uint256 gene) internal pure returns (uint256) {
        return getChromossome(gene, 0);
    }
}

File 11 of 15 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

// solhint-disable

/// @notice A modified version of Solmate's ERC721 (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
/// @author Solmate, Aleph Retamal <github.com/alephao>
/// @dev Note that balanceOf does not revert if passed the zero address, in defiance of the ERC.
abstract contract ERC721 {
    /*///////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed id
    );

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 indexed id
    );

    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );

    /*///////////////////////////////////////////////////////////////
                          METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*///////////////////////////////////////////////////////////////
                            ERC721 STORAGE                        
    //////////////////////////////////////////////////////////////*/

    mapping(address => uint256) public balanceOf;

    mapping(uint256 => address) public ownerOf;

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*///////////////////////////////////////////////////////////////
                              CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*///////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = ownerOf[id];

        require(
            msg.sender == owner || isApprovedForAll[owner][msg.sender],
            "NOT_AUTHORIZED"
        );

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function _transfer(
        address from,
        address to,
        uint256 id
    ) internal {
        require(from == ownerOf[id], "WRONG_FROM");

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            balanceOf[from]--;
            balanceOf[to]++;
        }

        ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from ||
                msg.sender == getApproved[id] ||
                isApprovedForAll[from][msg.sender],
            "NOT_AUTHORIZED"
        );

        _transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(
                    msg.sender,
                    from,
                    id,
                    ""
                ) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes memory data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(
                    msg.sender,
                    from,
                    id,
                    data
                ) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*///////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId)
        public
        pure
        virtual
        returns (bool)
    {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*///////////////////////////////////////////////////////////////
                       INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            balanceOf[to]++;
        }

        ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = ownerOf[id];

        require(ownerOf[id] != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            balanceOf[owner]--;
        }

        delete ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*///////////////////////////////////////////////////////////////
                       INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(
                    msg.sender,
                    address(0),
                    id,
                    ""
                ) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(
                    msg.sender,
                    address(0),
                    id,
                    data
                ) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
interface ERC721TokenReceiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 id,
        bytes calldata data
    ) external returns (bytes4);
}

File 12 of 15 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 13 of 15 : IAlphaDogsEvents.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

interface IAlphaDogsEvents {
    event NameChanged(uint256 indexed id, string name);
    event LoreChanged(uint256 indexed id, string lore);
    event Breeded(uint256 indexed child, uint256 mom, uint256 dad);
    event Staked(uint256 indexed id);
    event Unstaked(uint256 indexed id, uint256 amount);
    event ClaimedTokens(uint256 indexed id, uint256 amount);
}

File 14 of 15 : IAlphaDogsErrors.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

interface IAlphaDogsErrors {
    /// @dev 0x2783839d
    error InsufficientTokensAvailable();
    /// @dev 0x154e0758
    error InsufficientReservedTokensAvailable();
    /// @dev 0x8152a42e
    error InsufficientNonReservedTokensAvailable();
    /// @dev 0x53bb24f9
    error TokenLimitReached();
    /// @dev 0xb05e92fa
    error InvalidMerkleProof();
    /// @dev 0x2c5211c6
    error InvalidAmount();
    /// @dev 0x50e55ae1
    error InvalidAmountToClaim();
    /// @dev 0x6aa2a937
    error InvalidTokenID();
    /// @dev 0x1ae3550b
    error InvalidNameLength();
    /// @dev 0x8a0fcaee
    error InvalidSameValue();
    /// @dev 0x2a7c6b6e
    error InvalidTokenOwner();
    /// @dev 0x8e8ede30
    error FusionWithSameParentsForbidden();
    /// @dev 0x6d074376
    error FusionWithPuppyForbidden();
    /// @dev 0x36a1c33f
    error NotChanged();
    /// @dev 0x80cb55e2
    error NotActive();
    /// @dev 0xb4fa3fb3
    error InvalidInput();
    /// @dev 0xddb5de5e
    error InvalidSender();
    /// @dev 0x21029e82
    error InvalidChar();
}

File 15 of 15 : Chromossomes.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.14;

// Generated code. Do not modify!

/// @title  AlphaDogs Chromossome Generator Library
/// @author Aleph Retamal <github.com/alephao>
/// @notice Library containing functions to pick AlphaDogs chromossomes from an uint256 seed.
library Chromossomes {
    // Each of those seedTo{Trait} function select 4 bytes from the seed
    // and use those selected bytes to pick a trait using the A.J. Walker
    // algorithm. The rarity and aliases are calculated beforehand.

    function seedToBackground(uint256 seed) internal pure returns (uint256) {
        unchecked {
            uint256 traitSeed = (seed >> 16) & 0xFFFF;
            uint256 trait = traitSeed % 21;
            if (
                traitSeed >> 8 <
                [
                    154,
                    222,
                    166,
                    200,
                    150,
                    333,
                    97,
                    158,
                    33,
                    162,
                    44,
                    170,
                    93,
                    234,
                    123,
                    94,
                    345,
                    134,
                    66,
                    255,
                    99
                ][trait]
            ) return trait;
            return
                [
                    1,
                    20,
                    1,
                    2,
                    1,
                    3,
                    3,
                    3,
                    5,
                    5,
                    13,
                    9,
                    16,
                    11,
                    16,
                    16,
                    13,
                    16,
                    19,
                    16,
                    19
                ][trait];
        }
    }

    function seedToFur(uint256 seed) internal pure returns (uint256) {
        unchecked {
            uint256 traitSeed = (seed >> 32) & 0xFFFF;
            uint256 trait = traitSeed % 12;
            if (
                traitSeed >> 8 <
                [44, 345, 299, 450, 460, 88, 166, 177, 369, 470, 188, 277][
                    trait
                ]
            ) return trait;
            return [3, 11, 1, 2, 3, 4, 9, 9, 4, 8, 9, 9][trait];
        }
    }

    function seedToNeck(uint256 seed) internal pure returns (uint256) {
        unchecked {
            uint256 traitSeed = (seed >> 48) & 0xFFFF;
            uint256 trait = traitSeed % 34;
            if (
                traitSeed >> 8 <
                [
                    140,
                    333,
                    147,
                    134,
                    878,
                    92,
                    53,
                    100,
                    25,
                    115,
                    90,
                    122,
                    40,
                    6,
                    9,
                    130,
                    3,
                    5,
                    222,
                    4,
                    45,
                    52,
                    57,
                    23,
                    98,
                    50,
                    48,
                    95,
                    27,
                    21,
                    55,
                    47,
                    32,
                    35
                ][trait]
            ) return trait;
            return
                [
                    33,
                    0,
                    1,
                    2,
                    3,
                    0,
                    1,
                    4,
                    1,
                    7,
                    1,
                    9,
                    1,
                    2,
                    4,
                    11,
                    4,
                    4,
                    15,
                    4,
                    4,
                    4,
                    4,
                    4,
                    4,
                    4,
                    4,
                    4,
                    4,
                    4,
                    9,
                    15,
                    18,
                    18
                ][trait];
        }
    }

    function seedToEyes(uint256 seed) internal pure returns (uint256) {
        unchecked {
            uint256 traitSeed = (seed >> 64) & 0xFFFF;
            uint256 trait = traitSeed % 43;
            if (
                traitSeed >> 8 <
                [
                    30,
                    21,
                    89,
                    7,
                    500,
                    135,
                    52,
                    59,
                    125,
                    88,
                    22,
                    81,
                    120,
                    228,
                    15,
                    90,
                    32,
                    39,
                    17,
                    83,
                    42,
                    12,
                    82,
                    100,
                    84,
                    20,
                    58,
                    56,
                    28,
                    180,
                    40,
                    35,
                    54,
                    55,
                    86,
                    85,
                    24,
                    53,
                    240,
                    80,
                    44,
                    26,
                    16
                ][trait]
            ) return trait;
            return
                [
                    4,
                    4,
                    42,
                    4,
                    2,
                    4,
                    4,
                    4,
                    5,
                    8,
                    4,
                    9,
                    11,
                    12,
                    4,
                    13,
                    4,
                    4,
                    5,
                    15,
                    8,
                    12,
                    19,
                    22,
                    23,
                    13,
                    13,
                    13,
                    13,
                    24,
                    22,
                    29,
                    29,
                    29,
                    29,
                    34,
                    35,
                    38,
                    35,
                    38,
                    38,
                    38,
                    39
                ][trait];
        }
    }

    function seedToHat(uint256 seed) internal pure returns (uint256) {
        unchecked {
            uint256 traitSeed = (seed >> 80) & 0xFFFF;
            uint256 trait = traitSeed % 68;
            if (
                traitSeed >> 8 <
                [
                    18,
                    4,
                    30,
                    35,
                    28,
                    45,
                    46,
                    25,
                    48,
                    22,
                    20,
                    1260,
                    38,
                    43,
                    24,
                    59,
                    38,
                    29,
                    56,
                    30,
                    7,
                    18,
                    25,
                    23,
                    58,
                    42,
                    22,
                    9,
                    6,
                    15,
                    35,
                    22,
                    12,
                    66,
                    27,
                    27,
                    44,
                    46,
                    37,
                    11,
                    28,
                    38,
                    15,
                    42,
                    40,
                    60,
                    37,
                    28,
                    53,
                    50,
                    15,
                    12,
                    5,
                    40,
                    30,
                    8,
                    18,
                    49,
                    48,
                    29,
                    30,
                    10,
                    44,
                    3,
                    35,
                    35,
                    46,
                    35
                ][trait]
            ) return trait;
            return
                [
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    67,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    15,
                    11,
                    11,
                    11,
                    11,
                    11,
                    18,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    24,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    33,
                    11,
                    11,
                    45,
                    48,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    11,
                    18,
                    33,
                    33,
                    45,
                    49
                ][trait];
        }
    }

    function seedToMouth(uint256 seed) internal pure returns (uint256) {
        unchecked {
            uint256 traitSeed = (seed >> 96) & 0xFFFF;
            uint256 trait = traitSeed % 18;
            if (
                traitSeed >> 8 <
                [
                    156,
                    96,
                    1480,
                    48,
                    333,
                    96,
                    84,
                    32,
                    156,
                    72,
                    24,
                    60,
                    72,
                    84,
                    120,
                    120,
                    168,
                    132
                ][trait]
            ) return trait;
            return
                [2, 2, 17, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4][trait];
        }
    }

    function seedToNosering(uint256 seed) internal pure returns (uint256) {
        unchecked {
            uint256 traitSeed = (seed >> 112) & 0xFFFF;
            uint256 trait = traitSeed % 4;
            if (traitSeed >> 8 < [3201, 12, 84, 36][trait]) return trait;
            return [3, 0, 0, 0][trait];
        }
    }
}

Settings
{
  "remappings": [
    "$/=src/",
    "@ds-test/=lib/ds-test/src/",
    "@forge-std/=lib/forge-std/src/",
    "@hevm/=lib/hevm/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "@solmate/=lib/solmate/src/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "solmate/=lib/solmate/src/",
    "src/=src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint32","name":"_maxGenesis","type":"uint32"},{"internalType":"uint32","name":"_maxPuppies","type":"uint32"},{"internalType":"uint32","name":"_maxReserved","type":"uint32"},{"internalType":"contract IAlphaToken","name":"_alphaToken","type":"address"},{"internalType":"contract IAlphaDogsAttributes","name":"_attributes","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FusionWithPuppyForbidden","type":"error"},{"inputs":[],"name":"FusionWithSameParentsForbidden","type":"error"},{"inputs":[],"name":"InsufficientNonReservedTokensAvailable","type":"error"},{"inputs":[],"name":"InsufficientReservedTokensAvailable","type":"error"},{"inputs":[],"name":"InsufficientTokensAvailable","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidAmountToClaim","type":"error"},{"inputs":[],"name":"InvalidChar","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidMerkleProof","type":"error"},{"inputs":[],"name":"InvalidNameLength","type":"error"},{"inputs":[],"name":"InvalidSameValue","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidTokenID","type":"error"},{"inputs":[],"name":"InvalidTokenOwner","type":"error"},{"inputs":[],"name":"NotActive","type":"error"},{"inputs":[],"name":"NotChanged","type":"error"},{"inputs":[],"name":"TokenLimitReached","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"child","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mom","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dad","type":"uint256"}],"name":"Breeded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"lore","type":"string"}],"name":"LoreChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","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":"uint256","name":"id","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"BREEDING_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GENESIS_TOKEN_PER_DAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PUPPY_TOKEN_PER_DAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPDATE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"alphaToken","outputs":[{"internalType":"contract IAlphaToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"attributes","outputs":[{"internalType":"contract IAlphaDogsAttributes","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mom","type":"uint256"},{"internalType":"uint256","name":"dad","type":"uint256"}],"name":"breed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"didMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisLeft","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisNonReservedSupply","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisReservedSupply","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisSupply","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMetadata","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"lore","type":"string"}],"internalType":"struct IAlphaDogs.CustomMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getStake","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint96","name":"stakedAt","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSaleActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSupplyReserved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGenesis","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPuppies","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReserved","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"nonpayable","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":"","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"premint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"puppySupply","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"puppyTokensLeft","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isSaleActive","type":"bool"}],"name":"setIsSaleActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isSupplyReserved","type":"bool"}],"name":"setIsSupplyReserved","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"newLore","type":"string"}],"name":"setLore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"newName","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101206040526001600755600880546001600160701b0319166101001790553480156200002b57600080fd5b5060405162004482380380620044828339810160408190526200004e9162000243565b6040805180820182526009815268416c706861446f677360b81b602080830191825283518085019094526002845261105160f21b90840152815191929162000099916000916200016a565b508051620000af9060019060208401906200016a565b505050620000cc620000c66200011460201b60201c565b62000118565b63ffffffff95861660805293851660a05291909316610100526001600160a01b0392831660c052600c8054919093166001600160a01b03199091161790915560e052620002fe565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8280546200017890620002c2565b90600052602060002090601f0160209004810192826200019c5760008555620001e7565b82601f10620001b757805160ff1916838001178555620001e7565b82800160010185558215620001e7579182015b82811115620001e7578251825591602001919060010190620001ca565b50620001f5929150620001f9565b5090565b5b80821115620001f55760008155600101620001fa565b805163ffffffff811681146200022557600080fd5b919050565b6001600160a01b03811681146200024057600080fd5b50565b60008060008060008060c087890312156200025d57600080fd5b620002688762000210565b9550620002786020880162000210565b9450620002886040880162000210565b935060608701516200029a816200022a565b6080880151909350620002ad816200022a565b8092505060a087015190509295509295509295565b600181811c90821680620002d757607f821691505b602082108103620002f857634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e051610100516140e46200039e6000396000818161060901528181610b5e0152610ce00152600081816103be0152610dfe0152600081816105490152818161119201528181611aad01528181611de001526125300152600081816104c60152818161071301526119b101526000818161049f01528181610af301528181610b7f01528181610d34015261137501526140e46000f3fe608060405234801561001057600080fd5b50600436106102a05760003560e01c8063715018a611610167578063b88d4fde116100ce578063e449f34111610087578063e449f34114610738578063e86b0b2c1461074b578063e985e9c51461075b578063f2fde38b14610789578063fc2567e51461079c578063fe55932a146107ab57600080fd5b8063b88d4fde14610653578063c87b56dd14610666578063ce325bf814610679578063d2d65ff5146106db578063d9ecad7b146106ee578063dd5d7bf51461070157600080fd5b806395d89b411161012057806395d89b41146105c9578063a22cb465146105d1578063a574cea4146105e4578063a9898fd914610604578063ad851b1a1461062b578063ae06eeaa1461063d57600080fd5b8063715018a61461056b578063740954e1146105735780638b1658f71461058a5780638d91371d146105925780638da5cb5b146105a557806393e1ea41146105b657600080fd5b806341bf25371161020b5780635fabe446116101c45780635fabe4461461049a578063623b49c4146104c15780636352211e146104e85780636ba4c1381461051157806370a082311461052457806370b4c9e01461054457600080fd5b806341bf25371461042457806342842e0e146104335780634bbf179b146104465780635398d31214610466578063564566a81461047d5780635a2d6dd51461048a57600080fd5b806318160ddd1161025d57806318160ddd14610353578063202ee58c1461039357806323b872dd146103a65780632eb4a7ab146103b95780633241e917146103ee5780633ef628a31461041157600080fd5b806301ffc9a7146102a557806306fdde03146102cd578063081812fc146102e2578063095ea7b3146103235780630fbf0a93146103385780631249c58b1461034b575b600080fd5b6102b86102b33660046138ed565b6107be565b60405190151581526020015b60405180910390f35b6102d5610810565b6040516102c49190613962565b61030b6102f0366004613975565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016102c4565b6103366103313660046139aa565b61089e565b005b610336610346366004613a20565b610985565b610336610a82565b61037e60085462010000810463ffffffff908116600160301b8304821601600160501b909204160190565b60405163ffffffff90911681526020016102c4565b6103366103a1366004613a20565b610c73565b6103366103b4366004613a62565b610ee6565b6103e07f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016102c4565b6102b86103fc366004613a9e565b600b6020526000908152604090205460ff1681565b61033661041f366004613ab9565b610fd3565b6103e06722b1c8c1227a000081565b610336610441366004613a62565b61123a565b60085462010000810463ffffffff908116600160301b909204160161037e565b60085461037e90600160501b900463ffffffff1681565b6008546102b89060ff1681565b6103e068056bc75e2d6310000081565b61037e7f000000000000000000000000000000000000000000000000000000000000000081565b61037e7f000000000000000000000000000000000000000000000000000000000000000081565b61030b6104f6366004613975565b6003602052600090815260409020546001600160a01b031681565b61033661051f366004613a20565b61130a565b6103e0610532366004613a9e565b60026020526000908152604090205481565b61030b7f000000000000000000000000000000000000000000000000000000000000000081565b61033661131a565b60085461037e90600160301b900463ffffffff1681565b61037e611350565b6103366105a0366004613b45565b61139a565b6006546001600160a01b031661030b565b600c5461030b906001600160a01b031681565b6102d5611411565b6103366105df366004613b60565b61141e565b6105f76105f2366004613975565b61148a565b6040516102c49190613b93565b61037e7f000000000000000000000000000000000000000000000000000000000000000081565b6008546102b890610100900460ff1681565b60085461037e9062010000900463ffffffff1681565b610336610661366004613c44565b6115e0565b6102d5610674366004613975565b61169c565b6106b4610687366004613975565b600a602052600090815260409020546001600160a01b03811690600160a01b90046001600160601b031682565b604080516001600160a01b0390931683526001600160601b039091166020830152016102c4565b6103366106e9366004613b45565b611896565b6103366106fc366004613cef565b6118fe565b600854600160501b900463ffffffff167f00000000000000000000000000000000000000000000000000000000000000000361037e565b610336610746366004613a20565b611b5e565b6103e0682086ac35105260000081565b6102b8610769366004613d11565b600560209081526000928352604080842090915290825290205460ff1681565b610336610797366004613a9e565b611b6a565b6103e0678ac7230489e8000081565b6103366107b9366004613ab9565b611c05565b60006301ffc9a760e01b6001600160e01b0319831614806107ef57506380ac58cd60e01b6001600160e01b03198316145b8061080a5750635b5e139f60e01b6001600160e01b03198316145b92915050565b6000805461081d90613d3b565b80601f016020809104026020016040519081016040528092919081815260200182805461084990613d3b565b80156108965780601f1061086b57610100808354040283529160200191610896565b820191906000526020600020905b81548152906001019060200180831161087957829003601f168201915b505050505081565b6000818152600360205260409020546001600160a01b0316338114806108e757506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b6109295760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60008190036109a75760405163b4fa3fb360e01b815260040160405180910390fd5b336109c557604051636edaef2f60e11b815260040160405180910390fd5b6000805b82811015610a7c578383828181106109e3576109e3613d6f565b604080518082018252338082526001600160601b03428116602084810191825295860297909701356000818152600a9096529390942091519551909316600160a01b026001600160a01b039590951694909417909355919350610a499190503084611e76565b60405182907feebbaa86c348cb664e392b180fd0ff2e1998af9fa833ef69a778cb0b42d3ca2790600090a26001016109c9565b50505050565b60085460ff16610aa557604051634065aaf160e11b815260040160405180910390fd5b336000908152600b602052604090205460ff1615610ad6576040516353bb24f960e01b815260040160405180910390fd5b60085463ffffffff600160301b82048116916201000090048116907f000000000000000000000000000000000000000000000000000000000000000016610b1d8284613d9b565b610b28906002613d9b565b1115610b4757604051632783839d60e01b815260040160405180910390fd5b600854610100900460ff168015610bb65750610ba37f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000613db3565b63ffffffff16610bb4826002613d9b565b115b15610bd4576040516340a9521760e11b815260040160405180910390fd5b336000908152600b60205260408120805460ff19166001179055610c0f600854600160301b810463ffffffff90811662010000909204160190565b6008805465ffffffff0000198116600263ffffffff6201000093849004811691909101811690920217909155169050610c5b33610c56610c5160018501611f5b565b611fb3565b611ffa565b610c6e33610c56610c5184600201611f5b565b505050565b60085460ff16610c9657604051634065aaf160e11b815260040160405180910390fd5b600854336000908152600b6020526040902054600160301b90910463ffffffff169060ff1615610cd9576040516353bb24f960e01b815260040160405180910390fd5b63ffffffff7f000000000000000000000000000000000000000000000000000000000000000016610d0b826002613d9b565b1115610d2a576040516302a9c0eb60e31b815260040160405180910390fd5b60085463ffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691610d6891620100009091041683613d9b565b610d73906002613d9b565b1115610d9257604051632783839d60e01b815260040160405180910390fd5b6000610d9f3360146120c6565b604051602001610daf9190613dd8565b6040516020818303038152906040528051906020012090506000610e298585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152507f000000000000000000000000000000000000000000000000000000000000000092508691506122629050565b905080610e495760405163582f497d60e11b815260040160405180910390fd5b336000908152600b60205260408120805460ff19166001179055610e84600854600160301b810463ffffffff90811662010000909204160190565b6008805469ffffffff000000000000198116600263ffffffff600160301b93849004811691909101811690920217909155169050610ecb33610c56610c5160018501611f5b565b610ede33610c56610c5184600201611f5b565b505050505050565b6001600160a01b038216610f305760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610920565b336001600160a01b0384161480610f5d57506000818152600460205260409020546001600160a01b031633145b80610f8b57506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b610fc85760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610920565b610c6e838383611e76565b60008381526003602052604090205483906001600160a01b0316331461100c5760405163153e35b760e11b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b81518110156110c757600082828151811061106657611066613d6f565b01602001516001600160f81b0319169050601160f91b8114806110965750601760fa1b6001600160f81b03198216145b156110b4576040516310814f4160e11b815260040160405180910390fd5b50806110bf81613df4565b915050611049565b50600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052508c81526009602052604090819020905194955061112394600190910193509150613e0d9050565b604051809103902081805190602001200361115157604051634507e57760e11b815260040160405180910390fd5b600088815260096020526040902061116d90600101888861383e565b50604051632770a7eb60e21b815233600482015268056bc75e2d6310000060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639dc29fac90604401600060405180830381600087803b1580156111de57600080fd5b505af11580156111f2573d6000803e3d6000fd5b50505050877f1d83c2282d074aad212f8c5d02271066bf42c603a85c4c9e4f07d1eb8c1998218888604051611228929190613ea8565b60405180910390a25050505050505050565b611245838383610ee6565b6001600160a01b0382163b15806112ee5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156112be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e29190613ed7565b6001600160e01b031916145b610c6e5760405162461bcd60e51b815260040161092090613ef4565b61131682826000612278565b5050565b6006546001600160a01b031633146113445760405162461bcd60e51b815260040161092090613f1e565b61134e600061259d565b565b6000611373600854600160301b810463ffffffff90811662010000909204160190565b7f000000000000000000000000000000000000000000000000000000000000000003905090565b6006546001600160a01b031633146113c45760405162461bcd60e51b815260040161092090613f1e565b801515600860019054906101000a900460ff161515036113f7576040516336a1c33f60e01b815260040160405180910390fd5b600880549115156101000261ff0019909216919091179055565b6001805461081d90613d3b565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60408051808201909152606080825260208201526000828152600960205260409081902081518083019092528054829082906114c590613d3b565b80601f01602080910402602001604051908101604052809291908181526020018280546114f190613d3b565b801561153e5780601f106115135761010080835404028352916020019161153e565b820191906000526020600020905b81548152906001019060200180831161152157829003601f168201915b5050505050815260200160018201805461155790613d3b565b80601f016020809104026020016040519081016040528092919081815260200182805461158390613d3b565b80156115d05780601f106115a5576101008083540402835291602001916115d0565b820191906000526020600020905b8154815290600101906020018083116115b357829003601f168201915b5050505050815250509050919050565b6115eb848484610ee6565b6001600160a01b0383163b15806116805750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290611631903390899088908890600401613f53565b6020604051808303816000875af1158015611650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116749190613ed7565b6001600160e01b031916145b610a7c5760405162461bcd60e51b815260040161092090613ef4565b6000818152600360205260409020546060906001600160a01b03166116d457604051636aa2a93760e01b815260040160405180910390fd5b60008281526009602052604080822081518083019092528054829082906116fa90613d3b565b80601f016020809104026020016040519081016040528092919081815260200182805461172690613d3b565b80156117735780601f1061174857610100808354040283529160200191611773565b820191906000526020600020905b81548152906001019060200180831161175657829003601f168201915b5050505050815260200160018201805461178c90613d3b565b80601f01602080910402602001604051908101604052809291908181526020018280546117b890613d3b565b80156118055780601f106117da57610100808354040283529160200191611805565b820191906000526020600020905b8154815290600101906020018083116117e857829003601f168201915b505050919092525050600c54825160208401516040516328de0f2f60e01b81529495506001600160a01b03909216936328de0f2f935061184a92889291600401613f90565b600060405180830381865afa158015611867573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261188f9190810190613fbb565b9392505050565b6006546001600160a01b031633146118c05760405162461bcd60e51b815260040161092090613f1e565b60085481151560ff9091161515036118eb576040516336a1c33f60e01b815260040160405180910390fd5b6008805460ff1916911515919091179055565b60008281526003602052604090205482906001600160a01b031633146119375760405163153e35b760e11b815260040160405180910390fd5b60008281526003602052604090205482906001600160a01b031633146119705760405163153e35b760e11b815260040160405180910390fd5b611978611350565b63ffffffff161561199c57604051634065aaf160e11b815260040160405180910390fd5b60085463ffffffff600160501b9091048116907f00000000000000000000000000000000000000000000000000000000000000001681036119f057604051632783839d60e01b815260040160405180910390fd5b60ff60381b8516151580611a09575060ff60381b841615155b15611a2757604051633683a1bb60e11b815260040160405180910390fd5b838503611a47576040516308e8ede360e41b815260040160405180910390fd5b60088054600163ffffffff600160501b808404821692909201160263ffffffff60501b199091161790556000611a868686611a8185611f5b565b6125ef565b604051632770a7eb60e21b8152336004820152682086ac35105260000060248201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639dc29fac90604401600060405180830381600087803b158015611af957600080fd5b505af1158015611b0d573d6000803e3d6000fd5b50505050611b1b338261263a565b604080518781526020810187905282917fbd17f74f642cef9b3214e44a57847f2240c00de2a13ef51b84a7a1c7fc2e1a38910160405180910390a2505050505050565b61131682826001612278565b6006546001600160a01b03163314611b945760405162461bcd60e51b815260040161092090613f1e565b6001600160a01b038116611bf95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610920565b611c028161259d565b50565b60008381526003602052604090205483906001600160a01b03163314611c3e5760405163153e35b760e11b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b8151811015611cf9576000828281518110611c9857611c98613d6f565b01602001516001600160f81b0319169050601160f91b811480611cc85750601760fa1b6001600160f81b03198216145b15611ce6576040516310814f4160e11b815260040160405180910390fd5b5080611cf181613df4565b915050611c7b565b50600086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508251929350505060191015611d5857604051631ae3550b60e01b815260040160405180910390fd5b600088815260096020526040908190209051611d749190613e0d565b6040518091039020818051906020012003611da257604051634507e57760e11b815260040160405180910390fd5b6000888152600960205260409020611dbb90888861383e565b50604051632770a7eb60e21b815233600482015268056bc75e2d6310000060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639dc29fac90604401600060405180830381600087803b158015611e2c57600080fd5b505af1158015611e40573d6000803e3d6000fd5b50505050877f8edfa912e70e283a8ef6d6f52cd1faef9690ff989eff2f11a134e8478ba7b28b8888604051611228929190613ea8565b6000818152600360205260409020546001600160a01b03848116911614611ecc5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610920565b6001600160a01b0380841660008181526002602090815260408083208054600019019055938616808352848320805460010190558583526003825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6040516bffffffffffffffffffffffff193260601b1660208201523a60348201526054810182905243607482015242609482015260009060b40160408051601f19818403018152919052805160209091012092915050565b6000611fbe82612745565b905060035b6000828152600360205260409020546001600160a01b031615611ff457611fea82826127a4565b9150600101611fc3565b50919050565b612004828261263a565b6001600160a01b0382163b15806120aa5750604051630a85bd0160e11b80825233600483015260006024830181905260448301849052608060648401526084830152906001600160a01b0384169063150b7a029060a4016020604051808303816000875af115801561207a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209e9190613ed7565b6001600160e01b031916145b6113165760405162461bcd60e51b815260040161092090613ef4565b606060006120d5836002614029565b6120e0906002613d9b565b67ffffffffffffffff8111156120f8576120f8613bd5565b6040519080825280601f01601f191660200182016040528015612122576020820181803683370190505b509050600360fc1b8160008151811061213d5761213d613d6f565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061216c5761216c613d6f565b60200101906001600160f81b031916908160001a9053506000612190846002614029565b61219b906001613d9b565b90505b6001811115612213576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106121cf576121cf613d6f565b1a60f81b8282815181106121e5576121e5613d6f565b60200101906001600160f81b031916908160001a90535060049490941c9361220c81614048565b905061219e565b50831561188f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610920565b60008261226f8584612830565b14949350505050565b600082900361229a5760405163b4fa3fb360e01b815260040160405180910390fd5b336122b857604051636edaef2f60e11b815260040160405180910390fd5b60408051808201909152600080825260208201819052908190819060005b86811015612502578787828181106122f0576122f0613d6f565b602090810292909201356000818152600a84526040908190208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b031694820194909452909550935050331461235c5760405163153e35b760e11b815260040160405180910390fd5b600060ff60381b841661237757678ac7230489e80000612381565b6722b1c8c1227a00005b9050600183602001516001600160601b03161161239f5760006123d0565b6201518083602001516001600160601b0316426123bc919061405f565b6123c69083614029565b6123d0919061408c565b94506123dc8587613d9b565b9550861561247557604080518082018252600080825260016020808401918252888352600a9052929020905191516001600160601b0316600160a01b026001600160a01b0392909216919091179055612436303386611e76565b837ffe67007f52a1bf967323b00fd406f9028a8e8a88aec274e07a63b2fabacc64a78660405161246891815260200190565b60405180910390a26124f9565b84600003612496576040516350e55ae160e01b815260040160405180910390fd5b6000848152600a602090815260409182902080546001600160a01b0316600160a01b426001600160601b031602179055905186815285917f3484600735cc885760c6630a1ae8b9f01413e27ab9b4b8535ea9da57dda6e6b9910160405180910390a25b506001016122d6565b50836000036125145750505050505050565b6040516340c10f1960e01b8152336004820152602481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906340c10f1990604401600060405180830381600087803b15801561257c57600080fd5b505af1158015612590573d6000803e3d6000fd5b5050505050505050505050565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006125fc84848461289c565b905060035b6000828152600360205260409020546001600160a01b0316156126325761262882826127a4565b9150600101612601565b509392505050565b6001600160a01b0382166126845760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610920565b6000818152600360205260409020546001600160a01b0316156126da5760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610920565b6001600160a01b038216600081815260026020908152604080832080546001019055848352600390915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000612750826128ea565b1760081b61275d82612aa6565b1760081b61276a82612bc7565b1760081b61277782612e52565b1760081b61278482613162565b1760081b61279182613626565b1760081b61279e826137a2565b17919050565b6040805160e08101825260048152601c6020820152600b918101919091526046606082015260246080820152600a60a0820152601560c0820152600090600860078085069182029260ff841b928492811061280157612801613d6f565b602002015160ff166001878416851c018161281e5761281e614076565b06901b85821916179250505092915050565b600081815b845181101561263257600085828151811061285257612852613d6f565b602002602001015190508083116128785760008381526020829052604090209250612889565b600081815260208490526040902092505b508061289481613df4565b915050612835565b6000670100000000000000815b60078110156128e157600060016008830286901c16156128c957856128cb565b865b60ff600884021b169290921791506001016128a9565b50949350505050565b600061ffff601083901c1681601582604080516102a081018252609a815260de602082015260a69181019190915260c860608201526096608082015261014d60a0820152606160c0820152609e60e0820152602161010082015260a2610120820152602c61014082015260aa610160820152605d61018082015260ea6101a0820152607b6101c0820152605e6101e08201526101596102008201526086610220820152604261024082015260ff6102608201526063610280820152919006915081601581106129bb576129bb613d6f565b602002015161ffff16600883901c10156129d6579392505050565b604080516102a081018252600180825260146020830152918101829052600260608201526080810191909152600360a0820181905260c0820181905260e082015260056101008201819052610120820152600d6101408201819052600961016083015260106101808301819052600b6101a08401526101c083018190526101e083018190526102008301919091526102208201819052601361024083018190526102608301919091526102808201528160158110612a9657612a96613d6f565b602002015160ff16949350505050565b600061ffff602083901c1681600c826040805161018081018252602c8152610159602082015261012b918101919091526101c260608201526101cc6080820152605860a082015260a660c082015260b160e08201526101716101008201526101d661012082015260bc610140820152610115610160820152919006915081600c8110612b3457612b34613d6f565b602002015161ffff16600883901c1015612b4f579392505050565b60408051610180810182526003808252600b6020830152600192820192909252600260608201526080810191909152600460a08201819052600960c0830181905260e083018190526101008301919091526008610120830152610140820181905261016082015281600c8110612a9657612a96613d6f565b600061ffff603083901c16816022826040805161044081018252608c815261014d6020808301919091526093928201929092526086606082015261036e6080820152605c60a0820152603560c0820152606460e082015260196101008201526073610120820152605a610140820152607a610160820152602861018082015260066101a082015260096101c082015260826101e08201526003610200820152600561022082015260de6102408201526004610260820152602d61028082015260346102a082015260396102c082015260176102e0820152606261030082015260326103208201526030610340820152605f610360820152601b61038082015260156103a082015260376103c0820152602f6103e0820152610400810191909152602361042082015291900691508160228110612d0557612d05613d6f565b602002015161ffff16600883901c1015612d20579392505050565b60408051610440810182526021815260006020820181905260019282018390526002606083018190526003608084015260a083019190915260c08201839052600460e08301819052610100830184905260076101208401526101408301849052600961016084018190526101808401949094526101a08301919091526101c08201819052600b6101e083015261020082018190526102208201819052600f6102408301819052610260830182905261028083018290526102a083018290526102c083018290526102e08301829052610300830182905261032083018290526103408301829052610360830182905261038083018290526103a08301919091526103c08201929092526103e0810191909152601261040082018190526104208201528160228110612a9657612a96613d6f565b6040805161056081018252601e81526015602080830191909152605982840152600760608301526101f46080830152608760a0830152603460c0830152603b60e0830152607d610100830152605861012083015260166101408301526051610160830152607861018083015260e46101a0830152600f6101c0830152605a6101e0830152610200820152602761022082015260116102408201526053610260820152602a610280820152600c6102a082015260526102c082015260646102e082015260546103008201526014610320820152603a6103408201526038610360820152601c61038082015260b46103a082015260286103c082015260236103e08201526036610400820152603761042082015260566104408201526055610460820152601861048082015260356104a082015260f06104c082015260506104e0820152602c610500820152601a610520820152601061054082015260009183901c61ffff1690602b808306919082908110612fce57612fce613d6f565b602002015161ffff16600883901c1015612fe9579392505050565b6040805161056081018252600480825260208201819052602a92820192909252606081018290526002608082015260a0810182905260c0810182905260e08101829052600561010082018190526008610120830181905261014083018490526009610160840152600b610180840152600c6101a084018190526101c08401859052600d6101e085018190526102008501869052610220850195909552610240840192909252600f6102608401526102808301526102a082015260136102c082015260166102e08201819052601761030083015261032082018390526103408201839052610360820183905261038082019290925260186103a08201526103c0810191909152601d6103e082018190526104008201819052610420820181905261044082015260226104608201526023610480820181905260266104a083018190526104c08301919091526104e082018190526105008201819052610520820152602761054082015281602b8110612a9657612a96613d6f565b600061ffff605083901c16816044826040805161088081018252601280825260046020830152601e928201839052602360608301819052601c60808401819052602d60a0850152602e60c08501819052601960e08601819052603061010087018190526016610120880181905260146101408901526104ec61016089015260266101808901819052602b6101a08a015260186101c08a0152603b6101e08a01526102008901819052601d6102208a0181905260386102408b01526102608a018b905260076102808b01526102a08a018990526102c08a019490945260176102e08a0152603a6103008a0152602a6103208a018190526103408a0183905260096103608b015260066103808b0152600f6103a08b018190526103c08b018990526103e08b0193909352600c6104008b0181905260426104208c0152601b6104408c018190526104608c0152602c6104808c018190526104a08c0188905260256104c08d01819052600b6104e08e01526105008d018a90526105208d01949094526105408c018590526105608c019290925260286105808c01819052603c6105a08d01526105c08c01939093526105e08b019790975260356106008b015260326106208b01526106408a019290925261066089019590955260056106808901526106a08801949094526106c0870188905260086106e08801526107008701959095526031610720870152610740860194909452610760850193909352610780840194909452600a6107a08401526107c083019390935260036107e083015261080082018390526108208201839052610840820152610860810191909152919006915081604481106133d3576133d3613d6f565b602002015161ffff16600883901c10156133ee579392505050565b6040805161088081018252600b80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052604361016082015261018081018290526101a081018290526101c081018290526101e0810182905261020081018290526102208101829052600f610240820152610260810182905261028081018290526102a081018290526102c081018290526102e081018290526012610300820181905261032082018390526103408201839052610360820183905261038082018390526103a082018390526103c082018390526103e08201839052610400820183905260186104208301526104408201839052610460820183905261048082018390526104a082018390526104c082018390526104e082018390526105008201839052610520820183905261054082018390526105608201839052610580820183905260216105a083018190526105c083018490526105e08301849052602d610600840181905260306106208501526106408401859052610660840185905261068084018590526106a084018590526106c084018590526106e08401859052610700840185905261072084018590526107408401859052610760840185905261078084018590526107a084018590526107c08401949094526107e0830191909152610800820181905261082082015261084081019190915260316108608201528160448110612a9657612a96613d6f565b600061ffff606083901c16816012826040805161024081018252609c808252606060208084018290526105c89484019490945260308184015261014d608084015260a0830152605460c0830181905260e0830193909352610100820152604861012082018190526018610140830152603c6101608301526101808201526101a081019190915260786101c082018190526101e082015260a86102008201526084610220820152919006915081601281106136e2576136e2613d6f565b602002015161ffff16600883901c10156136fd579392505050565b6040805161024081018252600280825260208201819052601192820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081019190915260046101c082018190526101e0820181905261020082018190526102208201528160128110612a9657612a96613d6f565b600061ffff607083901c168160048260408051608081018252610c818152600c602082015260549181019190915260246060820152919006915081600481106137ed576137ed613d6f565b602002015161ffff16600883901c1015613808579392505050565b604080516080810182526003815260006020820181905291810182905260608101919091528160048110612a9657612a96613d6f565b82805461384a90613d3b565b90600052602060002090601f01602090048101928261386c57600085556138b2565b82601f106138855782800160ff198235161785556138b2565b828001600101855582156138b2579182015b828111156138b2578235825591602001919060010190613897565b506138be9291506138c2565b5090565b5b808211156138be57600081556001016138c3565b6001600160e01b031981168114611c0257600080fd5b6000602082840312156138ff57600080fd5b813561188f816138d7565b60005b8381101561392557818101518382015260200161390d565b83811115610a7c5750506000910152565b6000815180845261394e81602086016020860161390a565b601f01601f19169290920160200192915050565b60208152600061188f6020830184613936565b60006020828403121561398757600080fd5b5035919050565b80356001600160a01b03811681146139a557600080fd5b919050565b600080604083850312156139bd57600080fd5b6139c68361398e565b946020939093013593505050565b60008083601f8401126139e657600080fd5b50813567ffffffffffffffff8111156139fe57600080fd5b6020830191508360208260051b8501011115613a1957600080fd5b9250929050565b60008060208385031215613a3357600080fd5b823567ffffffffffffffff811115613a4a57600080fd5b613a56858286016139d4565b90969095509350505050565b600080600060608486031215613a7757600080fd5b613a808461398e565b9250613a8e6020850161398e565b9150604084013590509250925092565b600060208284031215613ab057600080fd5b61188f8261398e565b600080600060408486031215613ace57600080fd5b83359250602084013567ffffffffffffffff80821115613aed57600080fd5b818601915086601f830112613b0157600080fd5b813581811115613b1057600080fd5b876020828501011115613b2257600080fd5b6020830194508093505050509250925092565b803580151581146139a557600080fd5b600060208284031215613b5757600080fd5b61188f82613b35565b60008060408385031215613b7357600080fd5b613b7c8361398e565b9150613b8a60208401613b35565b90509250929050565b602081526000825160406020840152613baf6060840182613936565b90506020840151601f19848303016040850152613bcc8282613936565b95945050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c1457613c14613bd5565b604052919050565b600067ffffffffffffffff821115613c3657613c36613bd5565b50601f01601f191660200190565b60008060008060808587031215613c5a57600080fd5b613c638561398e565b9350613c716020860161398e565b925060408501359150606085013567ffffffffffffffff811115613c9457600080fd5b8501601f81018713613ca557600080fd5b8035613cb8613cb382613c1c565b613beb565b818152886020838501011115613ccd57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060408385031215613d0257600080fd5b50508035926020909101359150565b60008060408385031215613d2457600080fd5b613d2d8361398e565b9150613b8a6020840161398e565b600181811c90821680613d4f57607f821691505b602082108103611ff457634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115613dae57613dae613d85565b500190565b600063ffffffff83811690831681811015613dd057613dd0613d85565b039392505050565b60008251613dea81846020870161390a565b9190910192915050565b600060018201613e0657613e06613d85565b5060010190565b600080835481600182811c915080831680613e2957607f831692505b60208084108203613e4857634e487b7160e01b86526022600452602486fd5b818015613e5c5760018114613e6d57613e9a565b60ff19861689528489019650613e9a565b60008a81526020902060005b86811015613e925781548b820152908501908301613e79565b505084890196505b509498975050505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600060208284031215613ee957600080fd5b815161188f816138d7565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613f8690830184613936565b9695505050505050565b838152606060208201526000613fa96060830185613936565b8281036040840152613f868185613936565b600060208284031215613fcd57600080fd5b815167ffffffffffffffff811115613fe457600080fd5b8201601f81018413613ff557600080fd5b8051614003613cb382613c1c565b81815285602083850101111561401857600080fd5b613bcc82602083016020860161390a565b600081600019048311821515161561404357614043613d85565b500290565b60008161405757614057613d85565b506000190190565b60008282101561407157614071613d85565b500390565b634e487b7160e01b600052601260045260246000fd5b6000826140a957634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220b40d1322c89947cfe2e1c7b1ed3d78eda2ae0ea7cb554347b1ad5bc87fb7b41764736f6c634300080e00330000000000000000000000000000000000000000000000000000000000000d480000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000000af000000000000000000000000009a8fb018326a4647488ccb340c211f510a466d3000000000000000000000000e681ae8707182c2464a5d35d7da0571a6dbcc0a7f7e1834c49033499873f3d2f07bb694a1df120ee02569685aad60cf86424718c

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102a05760003560e01c8063715018a611610167578063b88d4fde116100ce578063e449f34111610087578063e449f34114610738578063e86b0b2c1461074b578063e985e9c51461075b578063f2fde38b14610789578063fc2567e51461079c578063fe55932a146107ab57600080fd5b8063b88d4fde14610653578063c87b56dd14610666578063ce325bf814610679578063d2d65ff5146106db578063d9ecad7b146106ee578063dd5d7bf51461070157600080fd5b806395d89b411161012057806395d89b41146105c9578063a22cb465146105d1578063a574cea4146105e4578063a9898fd914610604578063ad851b1a1461062b578063ae06eeaa1461063d57600080fd5b8063715018a61461056b578063740954e1146105735780638b1658f71461058a5780638d91371d146105925780638da5cb5b146105a557806393e1ea41146105b657600080fd5b806341bf25371161020b5780635fabe446116101c45780635fabe4461461049a578063623b49c4146104c15780636352211e146104e85780636ba4c1381461051157806370a082311461052457806370b4c9e01461054457600080fd5b806341bf25371461042457806342842e0e146104335780634bbf179b146104465780635398d31214610466578063564566a81461047d5780635a2d6dd51461048a57600080fd5b806318160ddd1161025d57806318160ddd14610353578063202ee58c1461039357806323b872dd146103a65780632eb4a7ab146103b95780633241e917146103ee5780633ef628a31461041157600080fd5b806301ffc9a7146102a557806306fdde03146102cd578063081812fc146102e2578063095ea7b3146103235780630fbf0a93146103385780631249c58b1461034b575b600080fd5b6102b86102b33660046138ed565b6107be565b60405190151581526020015b60405180910390f35b6102d5610810565b6040516102c49190613962565b61030b6102f0366004613975565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016102c4565b6103366103313660046139aa565b61089e565b005b610336610346366004613a20565b610985565b610336610a82565b61037e60085462010000810463ffffffff908116600160301b8304821601600160501b909204160190565b60405163ffffffff90911681526020016102c4565b6103366103a1366004613a20565b610c73565b6103366103b4366004613a62565b610ee6565b6103e07ff7e1834c49033499873f3d2f07bb694a1df120ee02569685aad60cf86424718c81565b6040519081526020016102c4565b6102b86103fc366004613a9e565b600b6020526000908152604090205460ff1681565b61033661041f366004613ab9565b610fd3565b6103e06722b1c8c1227a000081565b610336610441366004613a62565b61123a565b60085462010000810463ffffffff908116600160301b909204160161037e565b60085461037e90600160501b900463ffffffff1681565b6008546102b89060ff1681565b6103e068056bc75e2d6310000081565b61037e7f0000000000000000000000000000000000000000000000000000000000000d4881565b61037e7f0000000000000000000000000000000000000000000000000000000000001a9081565b61030b6104f6366004613975565b6003602052600090815260409020546001600160a01b031681565b61033661051f366004613a20565b61130a565b6103e0610532366004613a9e565b60026020526000908152604090205481565b61030b7f00000000000000000000000009a8fb018326a4647488ccb340c211f510a466d381565b61033661131a565b60085461037e90600160301b900463ffffffff1681565b61037e611350565b6103366105a0366004613b45565b61139a565b6006546001600160a01b031661030b565b600c5461030b906001600160a01b031681565b6102d5611411565b6103366105df366004613b60565b61141e565b6105f76105f2366004613975565b61148a565b6040516102c49190613b93565b61037e7f0000000000000000000000000000000000000000000000000000000000000af081565b6008546102b890610100900460ff1681565b60085461037e9062010000900463ffffffff1681565b610336610661366004613c44565b6115e0565b6102d5610674366004613975565b61169c565b6106b4610687366004613975565b600a602052600090815260409020546001600160a01b03811690600160a01b90046001600160601b031682565b604080516001600160a01b0390931683526001600160601b039091166020830152016102c4565b6103366106e9366004613b45565b611896565b6103366106fc366004613cef565b6118fe565b600854600160501b900463ffffffff167f0000000000000000000000000000000000000000000000000000000000001a900361037e565b610336610746366004613a20565b611b5e565b6103e0682086ac35105260000081565b6102b8610769366004613d11565b600560209081526000928352604080842090915290825290205460ff1681565b610336610797366004613a9e565b611b6a565b6103e0678ac7230489e8000081565b6103366107b9366004613ab9565b611c05565b60006301ffc9a760e01b6001600160e01b0319831614806107ef57506380ac58cd60e01b6001600160e01b03198316145b8061080a5750635b5e139f60e01b6001600160e01b03198316145b92915050565b6000805461081d90613d3b565b80601f016020809104026020016040519081016040528092919081815260200182805461084990613d3b565b80156108965780601f1061086b57610100808354040283529160200191610896565b820191906000526020600020905b81548152906001019060200180831161087957829003601f168201915b505050505081565b6000818152600360205260409020546001600160a01b0316338114806108e757506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b6109295760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60008190036109a75760405163b4fa3fb360e01b815260040160405180910390fd5b336109c557604051636edaef2f60e11b815260040160405180910390fd5b6000805b82811015610a7c578383828181106109e3576109e3613d6f565b604080518082018252338082526001600160601b03428116602084810191825295860297909701356000818152600a9096529390942091519551909316600160a01b026001600160a01b039590951694909417909355919350610a499190503084611e76565b60405182907feebbaa86c348cb664e392b180fd0ff2e1998af9fa833ef69a778cb0b42d3ca2790600090a26001016109c9565b50505050565b60085460ff16610aa557604051634065aaf160e11b815260040160405180910390fd5b336000908152600b602052604090205460ff1615610ad6576040516353bb24f960e01b815260040160405180910390fd5b60085463ffffffff600160301b82048116916201000090048116907f0000000000000000000000000000000000000000000000000000000000000d4816610b1d8284613d9b565b610b28906002613d9b565b1115610b4757604051632783839d60e01b815260040160405180910390fd5b600854610100900460ff168015610bb65750610ba37f0000000000000000000000000000000000000000000000000000000000000af07f0000000000000000000000000000000000000000000000000000000000000d48613db3565b63ffffffff16610bb4826002613d9b565b115b15610bd4576040516340a9521760e11b815260040160405180910390fd5b336000908152600b60205260408120805460ff19166001179055610c0f600854600160301b810463ffffffff90811662010000909204160190565b6008805465ffffffff0000198116600263ffffffff6201000093849004811691909101811690920217909155169050610c5b33610c56610c5160018501611f5b565b611fb3565b611ffa565b610c6e33610c56610c5184600201611f5b565b505050565b60085460ff16610c9657604051634065aaf160e11b815260040160405180910390fd5b600854336000908152600b6020526040902054600160301b90910463ffffffff169060ff1615610cd9576040516353bb24f960e01b815260040160405180910390fd5b63ffffffff7f0000000000000000000000000000000000000000000000000000000000000af016610d0b826002613d9b565b1115610d2a576040516302a9c0eb60e31b815260040160405180910390fd5b60085463ffffffff7f0000000000000000000000000000000000000000000000000000000000000d48811691610d6891620100009091041683613d9b565b610d73906002613d9b565b1115610d9257604051632783839d60e01b815260040160405180910390fd5b6000610d9f3360146120c6565b604051602001610daf9190613dd8565b6040516020818303038152906040528051906020012090506000610e298585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152507ff7e1834c49033499873f3d2f07bb694a1df120ee02569685aad60cf86424718c92508691506122629050565b905080610e495760405163582f497d60e11b815260040160405180910390fd5b336000908152600b60205260408120805460ff19166001179055610e84600854600160301b810463ffffffff90811662010000909204160190565b6008805469ffffffff000000000000198116600263ffffffff600160301b93849004811691909101811690920217909155169050610ecb33610c56610c5160018501611f5b565b610ede33610c56610c5184600201611f5b565b505050505050565b6001600160a01b038216610f305760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610920565b336001600160a01b0384161480610f5d57506000818152600460205260409020546001600160a01b031633145b80610f8b57506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b610fc85760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610920565b610c6e838383611e76565b60008381526003602052604090205483906001600160a01b0316331461100c5760405163153e35b760e11b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b81518110156110c757600082828151811061106657611066613d6f565b01602001516001600160f81b0319169050601160f91b8114806110965750601760fa1b6001600160f81b03198216145b156110b4576040516310814f4160e11b815260040160405180910390fd5b50806110bf81613df4565b915050611049565b50600086868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052508c81526009602052604090819020905194955061112394600190910193509150613e0d9050565b604051809103902081805190602001200361115157604051634507e57760e11b815260040160405180910390fd5b600088815260096020526040902061116d90600101888861383e565b50604051632770a7eb60e21b815233600482015268056bc75e2d6310000060248201527f00000000000000000000000009a8fb018326a4647488ccb340c211f510a466d36001600160a01b031690639dc29fac90604401600060405180830381600087803b1580156111de57600080fd5b505af11580156111f2573d6000803e3d6000fd5b50505050877f1d83c2282d074aad212f8c5d02271066bf42c603a85c4c9e4f07d1eb8c1998218888604051611228929190613ea8565b60405180910390a25050505050505050565b611245838383610ee6565b6001600160a01b0382163b15806112ee5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156112be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e29190613ed7565b6001600160e01b031916145b610c6e5760405162461bcd60e51b815260040161092090613ef4565b61131682826000612278565b5050565b6006546001600160a01b031633146113445760405162461bcd60e51b815260040161092090613f1e565b61134e600061259d565b565b6000611373600854600160301b810463ffffffff90811662010000909204160190565b7f0000000000000000000000000000000000000000000000000000000000000d4803905090565b6006546001600160a01b031633146113c45760405162461bcd60e51b815260040161092090613f1e565b801515600860019054906101000a900460ff161515036113f7576040516336a1c33f60e01b815260040160405180910390fd5b600880549115156101000261ff0019909216919091179055565b6001805461081d90613d3b565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60408051808201909152606080825260208201526000828152600960205260409081902081518083019092528054829082906114c590613d3b565b80601f01602080910402602001604051908101604052809291908181526020018280546114f190613d3b565b801561153e5780601f106115135761010080835404028352916020019161153e565b820191906000526020600020905b81548152906001019060200180831161152157829003601f168201915b5050505050815260200160018201805461155790613d3b565b80601f016020809104026020016040519081016040528092919081815260200182805461158390613d3b565b80156115d05780601f106115a5576101008083540402835291602001916115d0565b820191906000526020600020905b8154815290600101906020018083116115b357829003601f168201915b5050505050815250509050919050565b6115eb848484610ee6565b6001600160a01b0383163b15806116805750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290611631903390899088908890600401613f53565b6020604051808303816000875af1158015611650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116749190613ed7565b6001600160e01b031916145b610a7c5760405162461bcd60e51b815260040161092090613ef4565b6000818152600360205260409020546060906001600160a01b03166116d457604051636aa2a93760e01b815260040160405180910390fd5b60008281526009602052604080822081518083019092528054829082906116fa90613d3b565b80601f016020809104026020016040519081016040528092919081815260200182805461172690613d3b565b80156117735780601f1061174857610100808354040283529160200191611773565b820191906000526020600020905b81548152906001019060200180831161175657829003601f168201915b5050505050815260200160018201805461178c90613d3b565b80601f01602080910402602001604051908101604052809291908181526020018280546117b890613d3b565b80156118055780601f106117da57610100808354040283529160200191611805565b820191906000526020600020905b8154815290600101906020018083116117e857829003601f168201915b505050919092525050600c54825160208401516040516328de0f2f60e01b81529495506001600160a01b03909216936328de0f2f935061184a92889291600401613f90565b600060405180830381865afa158015611867573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261188f9190810190613fbb565b9392505050565b6006546001600160a01b031633146118c05760405162461bcd60e51b815260040161092090613f1e565b60085481151560ff9091161515036118eb576040516336a1c33f60e01b815260040160405180910390fd5b6008805460ff1916911515919091179055565b60008281526003602052604090205482906001600160a01b031633146119375760405163153e35b760e11b815260040160405180910390fd5b60008281526003602052604090205482906001600160a01b031633146119705760405163153e35b760e11b815260040160405180910390fd5b611978611350565b63ffffffff161561199c57604051634065aaf160e11b815260040160405180910390fd5b60085463ffffffff600160501b9091048116907f0000000000000000000000000000000000000000000000000000000000001a901681036119f057604051632783839d60e01b815260040160405180910390fd5b60ff60381b8516151580611a09575060ff60381b841615155b15611a2757604051633683a1bb60e11b815260040160405180910390fd5b838503611a47576040516308e8ede360e41b815260040160405180910390fd5b60088054600163ffffffff600160501b808404821692909201160263ffffffff60501b199091161790556000611a868686611a8185611f5b565b6125ef565b604051632770a7eb60e21b8152336004820152682086ac35105260000060248201529091507f00000000000000000000000009a8fb018326a4647488ccb340c211f510a466d36001600160a01b031690639dc29fac90604401600060405180830381600087803b158015611af957600080fd5b505af1158015611b0d573d6000803e3d6000fd5b50505050611b1b338261263a565b604080518781526020810187905282917fbd17f74f642cef9b3214e44a57847f2240c00de2a13ef51b84a7a1c7fc2e1a38910160405180910390a2505050505050565b61131682826001612278565b6006546001600160a01b03163314611b945760405162461bcd60e51b815260040161092090613f1e565b6001600160a01b038116611bf95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610920565b611c028161259d565b50565b60008381526003602052604090205483906001600160a01b03163314611c3e5760405163153e35b760e11b815260040160405180910390fd5b8282600082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394505050505b8151811015611cf9576000828281518110611c9857611c98613d6f565b01602001516001600160f81b0319169050601160f91b811480611cc85750601760fa1b6001600160f81b03198216145b15611ce6576040516310814f4160e11b815260040160405180910390fd5b5080611cf181613df4565b915050611c7b565b50600086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508251929350505060191015611d5857604051631ae3550b60e01b815260040160405180910390fd5b600088815260096020526040908190209051611d749190613e0d565b6040518091039020818051906020012003611da257604051634507e57760e11b815260040160405180910390fd5b6000888152600960205260409020611dbb90888861383e565b50604051632770a7eb60e21b815233600482015268056bc75e2d6310000060248201527f00000000000000000000000009a8fb018326a4647488ccb340c211f510a466d36001600160a01b031690639dc29fac90604401600060405180830381600087803b158015611e2c57600080fd5b505af1158015611e40573d6000803e3d6000fd5b50505050877f8edfa912e70e283a8ef6d6f52cd1faef9690ff989eff2f11a134e8478ba7b28b8888604051611228929190613ea8565b6000818152600360205260409020546001600160a01b03848116911614611ecc5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610920565b6001600160a01b0380841660008181526002602090815260408083208054600019019055938616808352848320805460010190558583526003825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6040516bffffffffffffffffffffffff193260601b1660208201523a60348201526054810182905243607482015242609482015260009060b40160408051601f19818403018152919052805160209091012092915050565b6000611fbe82612745565b905060035b6000828152600360205260409020546001600160a01b031615611ff457611fea82826127a4565b9150600101611fc3565b50919050565b612004828261263a565b6001600160a01b0382163b15806120aa5750604051630a85bd0160e11b80825233600483015260006024830181905260448301849052608060648401526084830152906001600160a01b0384169063150b7a029060a4016020604051808303816000875af115801561207a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209e9190613ed7565b6001600160e01b031916145b6113165760405162461bcd60e51b815260040161092090613ef4565b606060006120d5836002614029565b6120e0906002613d9b565b67ffffffffffffffff8111156120f8576120f8613bd5565b6040519080825280601f01601f191660200182016040528015612122576020820181803683370190505b509050600360fc1b8160008151811061213d5761213d613d6f565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061216c5761216c613d6f565b60200101906001600160f81b031916908160001a9053506000612190846002614029565b61219b906001613d9b565b90505b6001811115612213576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106121cf576121cf613d6f565b1a60f81b8282815181106121e5576121e5613d6f565b60200101906001600160f81b031916908160001a90535060049490941c9361220c81614048565b905061219e565b50831561188f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610920565b60008261226f8584612830565b14949350505050565b600082900361229a5760405163b4fa3fb360e01b815260040160405180910390fd5b336122b857604051636edaef2f60e11b815260040160405180910390fd5b60408051808201909152600080825260208201819052908190819060005b86811015612502578787828181106122f0576122f0613d6f565b602090810292909201356000818152600a84526040908190208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b031694820194909452909550935050331461235c5760405163153e35b760e11b815260040160405180910390fd5b600060ff60381b841661237757678ac7230489e80000612381565b6722b1c8c1227a00005b9050600183602001516001600160601b03161161239f5760006123d0565b6201518083602001516001600160601b0316426123bc919061405f565b6123c69083614029565b6123d0919061408c565b94506123dc8587613d9b565b9550861561247557604080518082018252600080825260016020808401918252888352600a9052929020905191516001600160601b0316600160a01b026001600160a01b0392909216919091179055612436303386611e76565b837ffe67007f52a1bf967323b00fd406f9028a8e8a88aec274e07a63b2fabacc64a78660405161246891815260200190565b60405180910390a26124f9565b84600003612496576040516350e55ae160e01b815260040160405180910390fd5b6000848152600a602090815260409182902080546001600160a01b0316600160a01b426001600160601b031602179055905186815285917f3484600735cc885760c6630a1ae8b9f01413e27ab9b4b8535ea9da57dda6e6b9910160405180910390a25b506001016122d6565b50836000036125145750505050505050565b6040516340c10f1960e01b8152336004820152602481018590527f00000000000000000000000009a8fb018326a4647488ccb340c211f510a466d36001600160a01b0316906340c10f1990604401600060405180830381600087803b15801561257c57600080fd5b505af1158015612590573d6000803e3d6000fd5b5050505050505050505050565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006125fc84848461289c565b905060035b6000828152600360205260409020546001600160a01b0316156126325761262882826127a4565b9150600101612601565b509392505050565b6001600160a01b0382166126845760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610920565b6000818152600360205260409020546001600160a01b0316156126da5760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610920565b6001600160a01b038216600081815260026020908152604080832080546001019055848352600390915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000612750826128ea565b1760081b61275d82612aa6565b1760081b61276a82612bc7565b1760081b61277782612e52565b1760081b61278482613162565b1760081b61279182613626565b1760081b61279e826137a2565b17919050565b6040805160e08101825260048152601c6020820152600b918101919091526046606082015260246080820152600a60a0820152601560c0820152600090600860078085069182029260ff841b928492811061280157612801613d6f565b602002015160ff166001878416851c018161281e5761281e614076565b06901b85821916179250505092915050565b600081815b845181101561263257600085828151811061285257612852613d6f565b602002602001015190508083116128785760008381526020829052604090209250612889565b600081815260208490526040902092505b508061289481613df4565b915050612835565b6000670100000000000000815b60078110156128e157600060016008830286901c16156128c957856128cb565b865b60ff600884021b169290921791506001016128a9565b50949350505050565b600061ffff601083901c1681601582604080516102a081018252609a815260de602082015260a69181019190915260c860608201526096608082015261014d60a0820152606160c0820152609e60e0820152602161010082015260a2610120820152602c61014082015260aa610160820152605d61018082015260ea6101a0820152607b6101c0820152605e6101e08201526101596102008201526086610220820152604261024082015260ff6102608201526063610280820152919006915081601581106129bb576129bb613d6f565b602002015161ffff16600883901c10156129d6579392505050565b604080516102a081018252600180825260146020830152918101829052600260608201526080810191909152600360a0820181905260c0820181905260e082015260056101008201819052610120820152600d6101408201819052600961016083015260106101808301819052600b6101a08401526101c083018190526101e083018190526102008301919091526102208201819052601361024083018190526102608301919091526102808201528160158110612a9657612a96613d6f565b602002015160ff16949350505050565b600061ffff602083901c1681600c826040805161018081018252602c8152610159602082015261012b918101919091526101c260608201526101cc6080820152605860a082015260a660c082015260b160e08201526101716101008201526101d661012082015260bc610140820152610115610160820152919006915081600c8110612b3457612b34613d6f565b602002015161ffff16600883901c1015612b4f579392505050565b60408051610180810182526003808252600b6020830152600192820192909252600260608201526080810191909152600460a08201819052600960c0830181905260e083018190526101008301919091526008610120830152610140820181905261016082015281600c8110612a9657612a96613d6f565b600061ffff603083901c16816022826040805161044081018252608c815261014d6020808301919091526093928201929092526086606082015261036e6080820152605c60a0820152603560c0820152606460e082015260196101008201526073610120820152605a610140820152607a610160820152602861018082015260066101a082015260096101c082015260826101e08201526003610200820152600561022082015260de6102408201526004610260820152602d61028082015260346102a082015260396102c082015260176102e0820152606261030082015260326103208201526030610340820152605f610360820152601b61038082015260156103a082015260376103c0820152602f6103e0820152610400810191909152602361042082015291900691508160228110612d0557612d05613d6f565b602002015161ffff16600883901c1015612d20579392505050565b60408051610440810182526021815260006020820181905260019282018390526002606083018190526003608084015260a083019190915260c08201839052600460e08301819052610100830184905260076101208401526101408301849052600961016084018190526101808401949094526101a08301919091526101c08201819052600b6101e083015261020082018190526102208201819052600f6102408301819052610260830182905261028083018290526102a083018290526102c083018290526102e08301829052610300830182905261032083018290526103408301829052610360830182905261038083018290526103a08301919091526103c08201929092526103e0810191909152601261040082018190526104208201528160228110612a9657612a96613d6f565b6040805161056081018252601e81526015602080830191909152605982840152600760608301526101f46080830152608760a0830152603460c0830152603b60e0830152607d610100830152605861012083015260166101408301526051610160830152607861018083015260e46101a0830152600f6101c0830152605a6101e0830152610200820152602761022082015260116102408201526053610260820152602a610280820152600c6102a082015260526102c082015260646102e082015260546103008201526014610320820152603a6103408201526038610360820152601c61038082015260b46103a082015260286103c082015260236103e08201526036610400820152603761042082015260566104408201526055610460820152601861048082015260356104a082015260f06104c082015260506104e0820152602c610500820152601a610520820152601061054082015260009183901c61ffff1690602b808306919082908110612fce57612fce613d6f565b602002015161ffff16600883901c1015612fe9579392505050565b6040805161056081018252600480825260208201819052602a92820192909252606081018290526002608082015260a0810182905260c0810182905260e08101829052600561010082018190526008610120830181905261014083018490526009610160840152600b610180840152600c6101a084018190526101c08401859052600d6101e085018190526102008501869052610220850195909552610240840192909252600f6102608401526102808301526102a082015260136102c082015260166102e08201819052601761030083015261032082018390526103408201839052610360820183905261038082019290925260186103a08201526103c0810191909152601d6103e082018190526104008201819052610420820181905261044082015260226104608201526023610480820181905260266104a083018190526104c08301919091526104e082018190526105008201819052610520820152602761054082015281602b8110612a9657612a96613d6f565b600061ffff605083901c16816044826040805161088081018252601280825260046020830152601e928201839052602360608301819052601c60808401819052602d60a0850152602e60c08501819052601960e08601819052603061010087018190526016610120880181905260146101408901526104ec61016089015260266101808901819052602b6101a08a015260186101c08a0152603b6101e08a01526102008901819052601d6102208a0181905260386102408b01526102608a018b905260076102808b01526102a08a018990526102c08a019490945260176102e08a0152603a6103008a0152602a6103208a018190526103408a0183905260096103608b015260066103808b0152600f6103a08b018190526103c08b018990526103e08b0193909352600c6104008b0181905260426104208c0152601b6104408c018190526104608c0152602c6104808c018190526104a08c0188905260256104c08d01819052600b6104e08e01526105008d018a90526105208d01949094526105408c018590526105608c019290925260286105808c01819052603c6105a08d01526105c08c01939093526105e08b019790975260356106008b015260326106208b01526106408a019290925261066089019590955260056106808901526106a08801949094526106c0870188905260086106e08801526107008701959095526031610720870152610740860194909452610760850193909352610780840194909452600a6107a08401526107c083019390935260036107e083015261080082018390526108208201839052610840820152610860810191909152919006915081604481106133d3576133d3613d6f565b602002015161ffff16600883901c10156133ee579392505050565b6040805161088081018252600b80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052604361016082015261018081018290526101a081018290526101c081018290526101e0810182905261020081018290526102208101829052600f610240820152610260810182905261028081018290526102a081018290526102c081018290526102e081018290526012610300820181905261032082018390526103408201839052610360820183905261038082018390526103a082018390526103c082018390526103e08201839052610400820183905260186104208301526104408201839052610460820183905261048082018390526104a082018390526104c082018390526104e082018390526105008201839052610520820183905261054082018390526105608201839052610580820183905260216105a083018190526105c083018490526105e08301849052602d610600840181905260306106208501526106408401859052610660840185905261068084018590526106a084018590526106c084018590526106e08401859052610700840185905261072084018590526107408401859052610760840185905261078084018590526107a084018590526107c08401949094526107e0830191909152610800820181905261082082015261084081019190915260316108608201528160448110612a9657612a96613d6f565b600061ffff606083901c16816012826040805161024081018252609c808252606060208084018290526105c89484019490945260308184015261014d608084015260a0830152605460c0830181905260e0830193909352610100820152604861012082018190526018610140830152603c6101608301526101808201526101a081019190915260786101c082018190526101e082015260a86102008201526084610220820152919006915081601281106136e2576136e2613d6f565b602002015161ffff16600883901c10156136fd579392505050565b6040805161024081018252600280825260208201819052601192820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081019190915260046101c082018190526101e0820181905261020082018190526102208201528160128110612a9657612a96613d6f565b600061ffff607083901c168160048260408051608081018252610c818152600c602082015260549181019190915260246060820152919006915081600481106137ed576137ed613d6f565b602002015161ffff16600883901c1015613808579392505050565b604080516080810182526003815260006020820181905291810182905260608101919091528160048110612a9657612a96613d6f565b82805461384a90613d3b565b90600052602060002090601f01602090048101928261386c57600085556138b2565b82601f106138855782800160ff198235161785556138b2565b828001600101855582156138b2579182015b828111156138b2578235825591602001919060010190613897565b506138be9291506138c2565b5090565b5b808211156138be57600081556001016138c3565b6001600160e01b031981168114611c0257600080fd5b6000602082840312156138ff57600080fd5b813561188f816138d7565b60005b8381101561392557818101518382015260200161390d565b83811115610a7c5750506000910152565b6000815180845261394e81602086016020860161390a565b601f01601f19169290920160200192915050565b60208152600061188f6020830184613936565b60006020828403121561398757600080fd5b5035919050565b80356001600160a01b03811681146139a557600080fd5b919050565b600080604083850312156139bd57600080fd5b6139c68361398e565b946020939093013593505050565b60008083601f8401126139e657600080fd5b50813567ffffffffffffffff8111156139fe57600080fd5b6020830191508360208260051b8501011115613a1957600080fd5b9250929050565b60008060208385031215613a3357600080fd5b823567ffffffffffffffff811115613a4a57600080fd5b613a56858286016139d4565b90969095509350505050565b600080600060608486031215613a7757600080fd5b613a808461398e565b9250613a8e6020850161398e565b9150604084013590509250925092565b600060208284031215613ab057600080fd5b61188f8261398e565b600080600060408486031215613ace57600080fd5b83359250602084013567ffffffffffffffff80821115613aed57600080fd5b818601915086601f830112613b0157600080fd5b813581811115613b1057600080fd5b876020828501011115613b2257600080fd5b6020830194508093505050509250925092565b803580151581146139a557600080fd5b600060208284031215613b5757600080fd5b61188f82613b35565b60008060408385031215613b7357600080fd5b613b7c8361398e565b9150613b8a60208401613b35565b90509250929050565b602081526000825160406020840152613baf6060840182613936565b90506020840151601f19848303016040850152613bcc8282613936565b95945050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c1457613c14613bd5565b604052919050565b600067ffffffffffffffff821115613c3657613c36613bd5565b50601f01601f191660200190565b60008060008060808587031215613c5a57600080fd5b613c638561398e565b9350613c716020860161398e565b925060408501359150606085013567ffffffffffffffff811115613c9457600080fd5b8501601f81018713613ca557600080fd5b8035613cb8613cb382613c1c565b613beb565b818152886020838501011115613ccd57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b60008060408385031215613d0257600080fd5b50508035926020909101359150565b60008060408385031215613d2457600080fd5b613d2d8361398e565b9150613b8a6020840161398e565b600181811c90821680613d4f57607f821691505b602082108103611ff457634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115613dae57613dae613d85565b500190565b600063ffffffff83811690831681811015613dd057613dd0613d85565b039392505050565b60008251613dea81846020870161390a565b9190910192915050565b600060018201613e0657613e06613d85565b5060010190565b600080835481600182811c915080831680613e2957607f831692505b60208084108203613e4857634e487b7160e01b86526022600452602486fd5b818015613e5c5760018114613e6d57613e9a565b60ff19861689528489019650613e9a565b60008a81526020902060005b86811015613e925781548b820152908501908301613e79565b505084890196505b509498975050505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600060208284031215613ee957600080fd5b815161188f816138d7565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613f8690830184613936565b9695505050505050565b838152606060208201526000613fa96060830185613936565b8281036040840152613f868185613936565b600060208284031215613fcd57600080fd5b815167ffffffffffffffff811115613fe457600080fd5b8201601f81018413613ff557600080fd5b8051614003613cb382613c1c565b81815285602083850101111561401857600080fd5b613bcc82602083016020860161390a565b600081600019048311821515161561404357614043613d85565b500290565b60008161405757614057613d85565b506000190190565b60008282101561407157614071613d85565b500390565b634e487b7160e01b600052601260045260246000fd5b6000826140a957634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220b40d1322c89947cfe2e1c7b1ed3d78eda2ae0ea7cb554347b1ad5bc87fb7b41764736f6c634300080e0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000000000000000000000000000000000000000d480000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000000af000000000000000000000000009a8fb018326a4647488ccb340c211f510a466d3000000000000000000000000e681ae8707182c2464a5d35d7da0571a6dbcc0a7f7e1834c49033499873f3d2f07bb694a1df120ee02569685aad60cf86424718c

-----Decoded View---------------
Arg [0] : _maxGenesis (uint32): 3400
Arg [1] : _maxPuppies (uint32): 6800
Arg [2] : _maxReserved (uint32): 2800
Arg [3] : _alphaToken (address): 0x09A8fB018326A4647488CCB340C211f510A466d3
Arg [4] : _attributes (address): 0xe681aE8707182c2464A5d35D7dA0571A6dBCc0A7
Arg [5] : _merkleRoot (bytes32): 0xf7e1834c49033499873f3d2f07bb694a1df120ee02569685aad60cf86424718c

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000d48
Arg [1] : 0000000000000000000000000000000000000000000000000000000000001a90
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000af0
Arg [3] : 00000000000000000000000009a8fb018326a4647488ccb340c211f510a466d3
Arg [4] : 000000000000000000000000e681ae8707182c2464a5d35d7da0571a6dbcc0a7
Arg [5] : f7e1834c49033499873f3d2f07bb694a1df120ee02569685aad60cf86424718c


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.