ETH Price: $1,584.24 (-0.33%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Token

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 500000 runs

Other Settings:
default evmVersion
File 1 of 28 : Token.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { UUPS } from "../lib/proxy/UUPS.sol";
import { ReentrancyGuard } from "../lib/utils/ReentrancyGuard.sol";
import { ERC721Votes } from "../lib/token/ERC721Votes.sol";
import { ERC721 } from "../lib/token/ERC721.sol";
import { Ownable } from "../lib/utils/Ownable.sol";
import { TokenStorageV1 } from "./storage/TokenStorageV1.sol";
import { IBaseMetadata } from "./metadata/interfaces/IBaseMetadata.sol";
import { IManager } from "../manager/IManager.sol";
import { IAuction } from "../auction/IAuction.sol";
import { IToken } from "./IToken.sol";
import { VersionedContract } from "../VersionedContract.sol";

/// @title Token
/// @author Rohan Kulkarni
/// @custom:repo github.com/ourzora/nouns-protocol 
/// @notice A DAO's ERC-721 governance token
contract Token is IToken, VersionedContract, UUPS, Ownable, ReentrancyGuard, ERC721Votes, TokenStorageV1 {
    ///                                                          ///
    ///                         IMMUTABLES                       ///
    ///                                                          ///

    /// @notice The contract upgrade manager
    IManager private immutable manager;

    ///                                                          ///
    ///                         CONSTRUCTOR                      ///
    ///                                                          ///

    /// @param _manager The contract upgrade manager address
    constructor(address _manager) payable initializer {
        manager = IManager(_manager);
    }

    ///                                                          ///
    ///                         INITIALIZER                      ///
    ///                                                          ///

    /// @notice Initializes a DAO's ERC-721 token contract
    /// @param _founders The DAO founders
    /// @param _initStrings The encoded token and metadata initialization strings
    /// @param _metadataRenderer The token's metadata renderer
    /// @param _auction The token's auction house
    /// @param _initialOwner The initial owner of the token
    function initialize(
        IManager.FounderParams[] calldata _founders,
        bytes calldata _initStrings,
        address _metadataRenderer,
        address _auction,
        address _initialOwner
    ) external initializer {
        // Ensure the caller is the contract manager
        if (msg.sender != address(manager)) {
            revert ONLY_MANAGER();
        }

        // Initialize the reentrancy guard
        __ReentrancyGuard_init();

        // Setup ownable
        __Ownable_init(_initialOwner);

        // Store the founders and compute their allocations
        _addFounders(_founders);

        // Decode the token name and symbol
        (string memory _name, string memory _symbol, , , , ) = abi.decode(_initStrings, (string, string, string, string, string, string));

        // Initialize the ERC-721 token
        __ERC721_init(_name, _symbol);

        // Store the metadata renderer and auction house
        settings.metadataRenderer = IBaseMetadata(_metadataRenderer);
        settings.auction = _auction;
    }

    /// @notice Called by the auction upon the first unpause / token mint to transfer ownership from founder to treasury
    /// @dev Only callable by the auction contract
    function onFirstAuctionStarted() external override {
        if (msg.sender != settings.auction) {
            revert ONLY_AUCTION();
        }

        // Force transfer ownership to the treasury
        _transferOwnership(IAuction(settings.auction).treasury());
    }

    /// @notice Called upon initialization to add founders and compute their vesting allocations
    /// @dev We do this by reserving an mapping of [0-100] token indices, such that if a new token mint ID % 100 is reserved, it's sent to the appropriate founder.
    /// @param _founders The list of DAO founders
    function _addFounders(IManager.FounderParams[] calldata _founders) internal {
        // Used to store the total percent ownership among the founders
        uint256 totalOwnership;

        uint8 numFoundersAdded = 0;

        unchecked {
            // For each founder:
            for (uint256 i; i < _founders.length; ++i) {
                // Cache the percent ownership
                uint256 founderPct = _founders[i].ownershipPct;

                // Continue if no ownership is specified
                if (founderPct == 0) {
                    continue;
                }

                // Update the total ownership and ensure it's valid
                totalOwnership += founderPct;

                // Check that founders own less than 100% of tokens
                if (totalOwnership > 99) {
                    revert INVALID_FOUNDER_OWNERSHIP();
                }

                // Compute the founder's id
                uint256 founderId = numFoundersAdded++;

                // Get the pointer to store the founder
                Founder storage newFounder = founder[founderId];

                // Store the founder's vesting details
                newFounder.wallet = _founders[i].wallet;
                newFounder.vestExpiry = uint32(_founders[i].vestExpiry);
                // Total ownership cannot be above 100 so this fits safely in uint8
                newFounder.ownershipPct = uint8(founderPct);

                // Compute the vesting schedule
                uint256 schedule = 100 / founderPct;

                // Used to store the base token id the founder will recieve
                uint256 baseTokenId;

                // For each token to vest:
                for (uint256 j; j < founderPct; ++j) {
                    // Get the available token id
                    baseTokenId = _getNextTokenId(baseTokenId);

                    // Store the founder as the recipient
                    tokenRecipient[baseTokenId] = newFounder;

                    emit MintScheduled(baseTokenId, founderId, newFounder);

                    // Update the base token id
                    baseTokenId = (baseTokenId + schedule) % 100;
                }
            }

            // Store the founders' details
            settings.totalOwnership = uint8(totalOwnership);
            settings.numFounders = numFoundersAdded;
        }
    }

    /// @dev Finds the next available base token id for a founder
    /// @param _tokenId The ERC-721 token id
    function _getNextTokenId(uint256 _tokenId) internal view returns (uint256) {
        unchecked {
            while (tokenRecipient[_tokenId].wallet != address(0)) {
                _tokenId = (++_tokenId) % 100;
            }

            return _tokenId;
        }
    }

    ///                                                          ///
    ///                             MINT                         ///
    ///                                                          ///

    /// @notice Mints tokens to the auction house for bidding and handles founder vesting
    function mint() external nonReentrant returns (uint256 tokenId) {
        // Cache the auction address
        address minter = settings.auction;

        // Ensure the caller is the auction
        if (msg.sender != minter) {
            revert ONLY_AUCTION();
        }

        // Cannot realistically overflow
        unchecked {
            do {
                // Get the next token to mint
                tokenId = settings.mintCount++;

                // Lookup whether the token is for a founder, and mint accordingly if so
            } while (_isForFounder(tokenId));
        }

        // Mint the next available token to the auction house for bidding
        _mint(minter, tokenId);
    }

    /// @dev Overrides _mint to include attribute generation
    /// @param _to The token recipient
    /// @param _tokenId The ERC-721 token id
    function _mint(address _to, uint256 _tokenId) internal override {
        // Mint the token
        super._mint(_to, _tokenId);

        // Increment the total supply
        unchecked {
            ++settings.totalSupply;
        }

        // Generate the token attributes
        if (!settings.metadataRenderer.onMinted(_tokenId)) revert NO_METADATA_GENERATED();
    }

    /// @dev Checks if a given token is for a founder and mints accordingly
    /// @param _tokenId The ERC-721 token id
    function _isForFounder(uint256 _tokenId) private returns (bool) {
        // Get the base token id
        uint256 baseTokenId = _tokenId % 100;

        // If there is no scheduled recipient:
        if (tokenRecipient[baseTokenId].wallet == address(0)) {
            return false;

            // Else if the founder is still vesting:
        } else if (block.timestamp < tokenRecipient[baseTokenId].vestExpiry) {
            // Mint the token to the founder
            _mint(tokenRecipient[baseTokenId].wallet, _tokenId);

            return true;

            // Else the founder has finished vesting:
        } else {
            // Remove them from future lookups
            delete tokenRecipient[baseTokenId];

            return false;
        }
    }

    ///                                                          ///
    ///                             BURN                         ///
    ///                                                          ///

    /// @notice Burns a token that did not see any bids
    /// @param _tokenId The ERC-721 token id
    function burn(uint256 _tokenId) external {
        // Ensure the caller is the auction house
        if (msg.sender != settings.auction) {
            revert ONLY_AUCTION();
        }

        // Burn the token
        _burn(_tokenId);
    }

    function _burn(uint256 _tokenId) internal override {
        super._burn(_tokenId);

        unchecked {
            --settings.totalSupply;
        }
    }

    ///                                                          ///
    ///                           METADATA                       ///
    ///                                                          ///

    /// @notice The URI for a token
    /// @param _tokenId The ERC-721 token id
    function tokenURI(uint256 _tokenId) public view override(IToken, ERC721) returns (string memory) {
        return settings.metadataRenderer.tokenURI(_tokenId);
    }

    /// @notice The URI for the contract
    function contractURI() public view override(IToken, ERC721) returns (string memory) {
        return settings.metadataRenderer.contractURI();
    }

    ///                                                          ///
    ///                           FOUNDERS                       ///
    ///                                                          ///

    /// @notice The number of founders
    function totalFounders() external view returns (uint256) {
        return settings.numFounders;
    }

    /// @notice The founders total percent ownership
    function totalFounderOwnership() external view returns (uint256) {
        return settings.totalOwnership;
    }

    /// @notice The vesting details of a founder
    /// @param _founderId The founder id
    function getFounder(uint256 _founderId) external view returns (Founder memory) {
        return founder[_founderId];
    }

    /// @notice The vesting details of all founders
    function getFounders() external view returns (Founder[] memory) {
        // Cache the number of founders
        uint256 numFounders = settings.numFounders;

        // Get a temporary array to hold all founders
        Founder[] memory founders = new Founder[](numFounders);

        // Cannot realistically overflow
        unchecked {
            // Add each founder to the array
            for (uint256 i; i < numFounders; ++i) {
                founders[i] = founder[i];
            }
        }

        return founders;
    }

    /// @notice The founder scheduled to receive the given token id
    /// NOTE: If a founder is returned, there's no guarantee they'll receive the token as vesting expiration is not considered
    /// @param _tokenId The ERC-721 token id
    function getScheduledRecipient(uint256 _tokenId) external view returns (Founder memory) {
        return tokenRecipient[_tokenId % 100];
    }

    /// @notice Update the list of allocation owners
    /// @param newFounders the full list of founders
    function updateFounders(IManager.FounderParams[] calldata newFounders) external onlyOwner {
        // Cache the number of founders
        uint256 numFounders = settings.numFounders;

        // Get a temporary array to hold all founders
        Founder[] memory cachedFounders = new Founder[](numFounders);

        // Cannot realistically overflow
        unchecked {
            // Add each founder to the array
            for (uint256 i; i < numFounders; ++i) {
                cachedFounders[i] = founder[i];
            }
        }

        // Keep a mapping of all the reserved token IDs we're set to clear.
        bool[] memory clearedTokenIds = new bool[](100);

        unchecked {
            // for each existing founder:
            for (uint256 i; i < cachedFounders.length; ++i) {
                // copy the founder into memory
                Founder memory cachedFounder = cachedFounders[i];

                // Delete the founder from the stored mapping
                delete founder[i];

                // Some DAOs were initialized with 0 percentage ownership.
                // This skips them to avoid a division by zero error.
                if (cachedFounder.ownershipPct == 0) {
                    continue;
                }

                // using the ownership percentage, get reserved token percentages
                uint256 schedule = 100 / cachedFounder.ownershipPct;

                // Used to reverse engineer the indices the founder has reserved tokens in.
                uint256 baseTokenId;

                for (uint256 j; j < cachedFounder.ownershipPct; ++j) {
                    // Get the next index that hasn't already been cleared
                    while (clearedTokenIds[baseTokenId] != false) {
                        baseTokenId = (++baseTokenId) % 100;
                    }

                    delete tokenRecipient[baseTokenId];
                    clearedTokenIds[baseTokenId] = true;

                    emit MintUnscheduled(baseTokenId, i, cachedFounder);

                    // Update the base token id
                    baseTokenId = (baseTokenId + schedule) % 100;
                }
            }
        }

        settings.numFounders = 0;
        settings.totalOwnership = 0;
        emit FounderAllocationsCleared(newFounders);

        _addFounders(newFounders);
    }

    ///                                                          ///
    ///                           SETTINGS                       ///
    ///                                                          ///

    /// @notice The total supply of tokens
    function totalSupply() external view returns (uint256) {
        return settings.totalSupply;
    }

    /// @notice The address of the auction house
    function auction() external view returns (address) {
        return settings.auction;
    }

    /// @notice The address of the metadata renderer
    function metadataRenderer() external view returns (address) {
        return address(settings.metadataRenderer);
    }

    function owner() public view override(IToken, Ownable) returns (address) {
        return super.owner();
    }

    ///                                                          ///
    ///                         TOKEN UPGRADE                    ///
    ///                                                          ///

    /// @notice Ensures the caller is authorized to upgrade the contract and that the new implementation is valid
    /// @dev This function is called in `upgradeTo` & `upgradeToAndCall`
    /// @param _newImpl The new implementation address
    function _authorizeUpgrade(address _newImpl) internal view override {
        // Ensure the caller is the shared owner of the token and metadata renderer
        if (msg.sender != owner()) revert ONLY_OWNER();

        // Ensure the implementation is valid
        if (!manager.isRegisteredUpgrade(_getImplementation(), _newImpl)) revert INVALID_UPGRADE(_newImpl);
    }
}

File 2 of 28 : draft-IERC1822.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 3 of 28 : StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

File 4 of 28 : VersionedContract.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

abstract contract VersionedContract {
    function contractVersion() external pure returns (string memory) {
        return "1.1.0";
    }
}

File 5 of 28 : IAuction.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../lib/interfaces/IUUPS.sol";
import { IOwnable } from "../lib/interfaces/IOwnable.sol";
import { IPausable } from "../lib/interfaces/IPausable.sol";

/// @title IAuction
/// @author Rohan Kulkarni
/// @notice The external Auction events, errors, and functions
interface IAuction is IUUPS, IOwnable, IPausable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a bid is placed
    /// @param tokenId The ERC-721 token id
    /// @param bidder The address of the bidder
    /// @param amount The amount of ETH
    /// @param extended If the bid extended the auction
    /// @param endTime The end time of the auction
    event AuctionBid(uint256 tokenId, address bidder, uint256 amount, bool extended, uint256 endTime);

    /// @notice Emitted when an auction is settled
    /// @param tokenId The ERC-721 token id of the settled auction
    /// @param winner The address of the winning bidder
    /// @param amount The amount of ETH raised from the winning bid
    event AuctionSettled(uint256 tokenId, address winner, uint256 amount);

    /// @notice Emitted when an auction is created
    /// @param tokenId The ERC-721 token id of the created auction
    /// @param startTime The start time of the created auction
    /// @param endTime The end time of the created auction
    event AuctionCreated(uint256 tokenId, uint256 startTime, uint256 endTime);

    /// @notice Emitted when the auction duration is updated
    /// @param duration The new auction duration
    event DurationUpdated(uint256 duration);

    /// @notice Emitted when the reserve price is updated
    /// @param reservePrice The new reserve price
    event ReservePriceUpdated(uint256 reservePrice);

    /// @notice Emitted when the min bid increment percentage is updated
    /// @param minBidIncrementPercentage The new min bid increment percentage
    event MinBidIncrementPercentageUpdated(uint256 minBidIncrementPercentage);

    /// @notice Emitted when the time buffer is updated
    /// @param timeBuffer The new time buffer
    event TimeBufferUpdated(uint256 timeBuffer);

    ///                                                          ///
    ///                           ERRORS                         ///
    ///                                                          ///

    /// @dev Reverts if a bid is placed for the wrong token
    error INVALID_TOKEN_ID();

    /// @dev Reverts if a bid is placed for an auction thats over
    error AUCTION_OVER();

    /// @dev Reverts if a bid is placed for an auction that hasn't started
    error AUCTION_NOT_STARTED();

    /// @dev Reverts if attempting to settle an active auction
    error AUCTION_ACTIVE();

    /// @dev Reverts if attempting to settle an auction that was already settled
    error AUCTION_SETTLED();

    /// @dev Reverts if a bid does not meet the reserve price
    error RESERVE_PRICE_NOT_MET();

    /// @dev Reverts if a bid does not meet the minimum bid
    error MINIMUM_BID_NOT_MET();

    /// @dev Error for when the bid increment is set to 0.
    error MIN_BID_INCREMENT_1_PERCENT();

    /// @dev Reverts if the contract does not have enough ETH
    error INSOLVENT();

    /// @dev Reverts if the caller was not the contract manager
    error ONLY_MANAGER();

    /// @dev Thrown if the WETH contract throws a failure on transfer
    error FAILING_WETH_TRANSFER();

    /// @dev Thrown if the auction creation failed
    error AUCTION_CREATE_FAILED_TO_LAUNCH();

    ///                                                          ///
    ///                          FUNCTIONS                       ///
    ///                                                          ///

    /// @notice Initializes a DAO's auction house
    /// @param token The ERC-721 token address
    /// @param founder The founder responsible for starting the first auction
    /// @param treasury The treasury address where ETH will be sent
    /// @param duration The duration of each auction
    /// @param reservePrice The reserve price of each auction
    function initialize(
        address token,
        address founder,
        address treasury,
        uint256 duration,
        uint256 reservePrice
    ) external;

    /// @notice Creates a bid for the current token
    /// @param tokenId The ERC-721 token id
    function createBid(uint256 tokenId) external payable;

    /// @notice Settles the current auction and creates the next one
    function settleCurrentAndCreateNewAuction() external;

    /// @notice Settles the latest auction when the contract is paused
    function settleAuction() external;

    /// @notice Pauses the auction house
    function pause() external;

    /// @notice Unpauses the auction house
    function unpause() external;

    /// @notice The time duration of each auction
    function duration() external view returns (uint256);

    /// @notice The reserve price of each auction
    function reservePrice() external view returns (uint256);

    /// @notice The minimum amount of time to place a bid during an active auction
    function timeBuffer() external view returns (uint256);

    /// @notice The minimum percentage an incoming bid must raise the highest bid
    function minBidIncrement() external view returns (uint256);

    /// @notice Updates the time duration of each auction
    /// @param duration The new time duration
    function setDuration(uint256 duration) external;

    /// @notice Updates the reserve price of each auction
    /// @param reservePrice The new reserve price
    function setReservePrice(uint256 reservePrice) external;

    /// @notice Updates the time buffer of each auction
    /// @param timeBuffer The new time buffer
    function setTimeBuffer(uint256 timeBuffer) external;

    /// @notice Updates the minimum bid increment of each subsequent bid
    /// @param percentage The new percentage
    function setMinimumBidIncrement(uint256 percentage) external;

    /// @notice Get the address of the treasury
    function treasury() external returns (address);
}

File 6 of 28 : IEIP712.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IEIP712
/// @author Rohan Kulkarni
/// @notice The external EIP712 errors and functions
interface IEIP712 {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the deadline has passed to submit a signature
    error EXPIRED_SIGNATURE();

    /// @dev Reverts if the recovered signature is invalid
    error INVALID_SIGNATURE();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The sig nonce for an account
    /// @param account The account address
    function nonce(address account) external view returns (uint256);

    /// @notice The EIP-712 domain separator
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 7 of 28 : IERC1967Upgrade.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IERC1967Upgrade
/// @author Rohan Kulkarni
/// @notice The external ERC1967Upgrade events and errors
interface IERC1967Upgrade {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when the implementation is upgraded
    /// @param impl The address of the implementation
    event Upgraded(address impl);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if an implementation is an invalid upgrade
    /// @param impl The address of the invalid implementation
    error INVALID_UPGRADE(address impl);

    /// @dev Reverts if an implementation upgrade is not stored at the storage slot of the original
    error UNSUPPORTED_UUID();

    /// @dev Reverts if an implementation does not support ERC1822 proxiableUUID()
    error ONLY_UUPS();
}

File 8 of 28 : IERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IERC721
/// @author Rohan Kulkarni
/// @notice The external ERC721 events, errors, and functions
interface IERC721 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a token is transferred from sender to recipient
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /// @notice Emitted when an owner approves an account to manage a token
    /// @param owner The owner address
    /// @param approved The account address
    /// @param tokenId The ERC-721 token id
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /// @notice Emitted when an owner sets an approval for a spender to manage all tokens
    /// @param owner The owner address
    /// @param operator The spender address
    /// @param approved If the approval is being set or removed
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if a caller is not authorized to approve or transfer a token
    error INVALID_APPROVAL();

    /// @dev Reverts if a transfer is called with the incorrect token owner
    error INVALID_OWNER();

    /// @dev Reverts if a transfer is attempted to address(0)
    error INVALID_RECIPIENT();

    /// @dev Reverts if an existing token is called to be minted
    error ALREADY_MINTED();

    /// @dev Reverts if a non-existent token is called to be burned
    error NOT_MINTED();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The number of tokens owned
    /// @param owner The owner address
    function balanceOf(address owner) external view returns (uint256);

    /// @notice The owner of a token
    /// @param tokenId The ERC-721 token id
    function ownerOf(uint256 tokenId) external view returns (address);

    /// @notice The account approved to manage a token
    /// @param tokenId The ERC-721 token id
    function getApproved(uint256 tokenId) external view returns (address);

    /// @notice If an operator is authorized to manage all of an owner's tokens
    /// @param owner The owner address
    /// @param operator The operator address
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /// @notice Authorizes an account to manage a token
    /// @param to The account address
    /// @param tokenId The ERC-721 token id
    function approve(address to, uint256 tokenId) external;

    /// @notice Authorizes an account to manage all tokens
    /// @param operator The account address
    /// @param approved If permission is being given or removed
    function setApprovalForAll(address operator, bool approved) external;

    /// @notice Safe transfers a token from sender to recipient with additional data
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    /// @param data The additional data sent in the call to the recipient
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /// @notice Safe transfers a token from sender to recipient
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /// @notice Transfers a token from sender to recipient
    /// @param from The sender address
    /// @param to The recipient address
    /// @param tokenId The ERC-721 token id
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
}

File 9 of 28 : IERC721Votes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IERC721 } from "./IERC721.sol";
import { IEIP712 } from "./IEIP712.sol";

/// @title IERC721Votes
/// @author Rohan Kulkarni
/// @notice The external ERC721Votes events, errors, and functions
interface IERC721Votes is IERC721, IEIP712 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when an account changes their delegate
    event DelegateChanged(address indexed delegator, address indexed from, address indexed to);

    /// @notice Emitted when a delegate's number of votes is updated
    event DelegateVotesChanged(address indexed delegate, uint256 prevTotalVotes, uint256 newTotalVotes);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the timestamp provided isn't in the past
    error INVALID_TIMESTAMP();

    ///                                                          ///
    ///                            STRUCTS                       ///
    ///                                                          ///

    /// @notice The checkpoint data type
    /// @param timestamp The recorded timestamp
    /// @param votes The voting weight
    struct Checkpoint {
        uint64 timestamp;
        uint192 votes;
    }

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The current number of votes for an account
    /// @param account The account address
    function getVotes(address account) external view returns (uint256);

    /// @notice The number of votes for an account at a past timestamp
    /// @param account The account address
    /// @param timestamp The past timestamp
    function getPastVotes(address account, uint256 timestamp) external view returns (uint256);

    /// @notice The delegate for an account
    /// @param account The account address
    function delegates(address account) external view returns (address);

    /// @notice Delegates votes to an account
    /// @param to The address delegating votes to
    function delegate(address to) external;

    /// @notice Delegates votes from a signer to an account
    /// @param from The address delegating votes from
    /// @param to The address delegating votes to
    /// @param deadline The signature deadline
    /// @param v The 129th byte and chain id of the signature
    /// @param r The first 64 bytes of the signature
    /// @param s Bytes 64-128 of the signature
    function delegateBySig(
        address from,
        address to,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

File 10 of 28 : IInitializable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IInitializable
/// @author Rohan Kulkarni
/// @notice The external Initializable events and errors
interface IInitializable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when the contract has been initialized or reinitialized
    event Initialized(uint256 version);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if incorrectly initialized with address(0)
    error ADDRESS_ZERO();

    /// @dev Reverts if disabling initializers during initialization
    error INITIALIZING();

    /// @dev Reverts if calling an initialization function outside of initialization
    error NOT_INITIALIZING();

    /// @dev Reverts if reinitializing incorrectly
    error ALREADY_INITIALIZED();
}

File 11 of 28 : IOwnable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IOwnable
/// @author Rohan Kulkarni
/// @notice The external Ownable events, errors, and functions
interface IOwnable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when ownership has been updated
    /// @param prevOwner The previous owner address
    /// @param newOwner The new owner address
    event OwnerUpdated(address indexed prevOwner, address indexed newOwner);

    /// @notice Emitted when an ownership transfer is pending
    /// @param owner The current owner address
    /// @param pendingOwner The pending new owner address
    event OwnerPending(address indexed owner, address indexed pendingOwner);

    /// @notice Emitted when a pending ownership transfer has been canceled
    /// @param owner The current owner address
    /// @param canceledOwner The canceled owner address
    event OwnerCanceled(address indexed owner, address indexed canceledOwner);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if an unauthorized user calls an owner function
    error ONLY_OWNER();

    /// @dev Reverts if an unauthorized user calls a pending owner function
    error ONLY_PENDING_OWNER();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The address of the owner
    function owner() external view returns (address);

    /// @notice The address of the pending owner
    function pendingOwner() external view returns (address);

    /// @notice Forces an ownership transfer
    /// @param newOwner The new owner address
    function transferOwnership(address newOwner) external;

    /// @notice Initiates a two-step ownership transfer
    /// @param newOwner The new owner address
    function safeTransferOwnership(address newOwner) external;

    /// @notice Accepts an ownership transfer
    function acceptOwnership() external;

    /// @notice Cancels a pending ownership transfer
    function cancelOwnershipTransfer() external;
}

File 12 of 28 : IPausable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title IPausable
/// @author Rohan Kulkarni
/// @notice The external Pausable events, errors, and functions
interface IPausable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when the contract is paused
    /// @param user The address that paused the contract
    event Paused(address user);

    /// @notice Emitted when the contract is unpaused
    /// @param user The address that unpaused the contract
    event Unpaused(address user);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if called when the contract is paused
    error PAUSED();

    /// @dev Reverts if called when the contract is unpaused
    error UNPAUSED();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice If the contract is paused
    function paused() external view returns (bool);
}

File 13 of 28 : IUUPS.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import { IERC1967Upgrade } from "./IERC1967Upgrade.sol";

/// @title IUUPS
/// @author Rohan Kulkarni
/// @notice The external UUPS errors and functions
interface IUUPS is IERC1967Upgrade, IERC1822Proxiable {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if not called directly
    error ONLY_CALL();

    /// @dev Reverts if not called via delegatecall
    error ONLY_DELEGATECALL();

    /// @dev Reverts if not called via proxy
    error ONLY_PROXY();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice Upgrades to an implementation
    /// @param newImpl The new implementation address
    function upgradeTo(address newImpl) external;

    /// @notice Upgrades to an implementation with an additional function call
    /// @param newImpl The new implementation address
    /// @param data The encoded function call
    function upgradeToAndCall(address newImpl, bytes memory data) external payable;
}

File 14 of 28 : ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import { StorageSlot } from "@openzeppelin/contracts/utils/StorageSlot.sol";

import { IERC1967Upgrade } from "../interfaces/IERC1967Upgrade.sol";
import { Address } from "../utils/Address.sol";

/// @title ERC1967Upgrade
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/ERC1967/ERC1967Upgrade.sol)
/// - Uses custom errors declared in IERC1967Upgrade
/// - Removes ERC1967 admin and beacon support
abstract contract ERC1967Upgrade is IERC1967Upgrade {
    ///                                                          ///
    ///                          CONSTANTS                       ///
    ///                                                          ///

    /// @dev bytes32(uint256(keccak256('eip1967.proxy.rollback')) - 1)
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /// @dev bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    ///                                                          ///
    ///                          FUNCTIONS                       ///
    ///                                                          ///

    /// @dev Upgrades to an implementation with security checks for UUPS proxies and an additional function call
    /// @param _newImpl The new implementation address
    /// @param _data The encoded function call
    function _upgradeToAndCallUUPS(
        address _newImpl,
        bytes memory _data,
        bool _forceCall
    ) internal {
        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(_newImpl);
        } else {
            try IERC1822Proxiable(_newImpl).proxiableUUID() returns (bytes32 slot) {
                if (slot != _IMPLEMENTATION_SLOT) revert UNSUPPORTED_UUID();
            } catch {
                revert ONLY_UUPS();
            }

            _upgradeToAndCall(_newImpl, _data, _forceCall);
        }
    }

    /// @dev Upgrades to an implementation with an additional function call
    /// @param _newImpl The new implementation address
    /// @param _data The encoded function call
    function _upgradeToAndCall(
        address _newImpl,
        bytes memory _data,
        bool _forceCall
    ) internal {
        _upgradeTo(_newImpl);

        if (_data.length > 0 || _forceCall) {
            Address.functionDelegateCall(_newImpl, _data);
        }
    }

    /// @dev Performs an implementation upgrade
    /// @param _newImpl The new implementation address
    function _upgradeTo(address _newImpl) internal {
        _setImplementation(_newImpl);

        emit Upgraded(_newImpl);
    }

    /// @dev Stores the address of an implementation
    /// @param _impl The implementation address
    function _setImplementation(address _impl) private {
        if (!Address.isContract(_impl)) revert INVALID_UPGRADE(_impl);

        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = _impl;
    }

    /// @dev The address of the current implementation
    function _getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }
}

File 15 of 28 : UUPS.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../interfaces/IUUPS.sol";
import { ERC1967Upgrade } from "./ERC1967Upgrade.sol";

/// @title UUPS
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/utils/UUPSUpgradeable.sol)
/// - Uses custom errors declared in IUUPS
/// - Inherits a modern, minimal ERC1967Upgrade
abstract contract UUPS is IUUPS, ERC1967Upgrade {
    ///                                                          ///
    ///                          IMMUTABLES                      ///
    ///                                                          ///

    /// @dev The address of the implementation
    address private immutable __self = address(this);

    ///                                                          ///
    ///                           MODIFIERS                      ///
    ///                                                          ///

    /// @dev Ensures that execution is via proxy delegatecall with the correct implementation
    modifier onlyProxy() {
        if (address(this) == __self) revert ONLY_DELEGATECALL();
        if (_getImplementation() != __self) revert ONLY_PROXY();
        _;
    }

    /// @dev Ensures that execution is via direct call
    modifier notDelegated() {
        if (address(this) != __self) revert ONLY_CALL();
        _;
    }

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Hook to authorize an implementation upgrade
    /// @param _newImpl The new implementation address
    function _authorizeUpgrade(address _newImpl) internal virtual;

    /// @notice Upgrades to an implementation
    /// @param _newImpl The new implementation address
    function upgradeTo(address _newImpl) external onlyProxy {
        _authorizeUpgrade(_newImpl);
        _upgradeToAndCallUUPS(_newImpl, "", false);
    }

    /// @notice Upgrades to an implementation with an additional function call
    /// @param _newImpl The new implementation address
    /// @param _data The encoded function call
    function upgradeToAndCall(address _newImpl, bytes memory _data) external payable onlyProxy {
        _authorizeUpgrade(_newImpl);
        _upgradeToAndCallUUPS(_newImpl, _data, true);
    }

    /// @notice The storage slot of the implementation address
    function proxiableUUID() external view notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }
}

File 16 of 28 : ERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IERC721 } from "../interfaces/IERC721.sol";
import { Initializable } from "../utils/Initializable.sol";
import { ERC721TokenReceiver } from "../utils/TokenReceiver.sol";
import { Address } from "../utils/Address.sol";

/// @title ERC721
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/ERC721Upgradeable.sol)
/// - Uses custom errors declared in IERC721
abstract contract ERC721 is IERC721, Initializable {
    ///                                                          ///
    ///                            STORAGE                       ///
    ///                                                          ///

    /// @notice The token name
    string public name;

    /// @notice The token symbol
    string public symbol;

    /// @notice The token owners
    /// @dev ERC-721 token id => Owner
    mapping(uint256 => address) internal owners;

    /// @notice The owner balances
    /// @dev Owner => Balance
    mapping(address => uint256) internal balances;

    /// @notice The token approvals
    /// @dev ERC-721 token id => Manager
    mapping(uint256 => address) internal tokenApprovals;

    /// @notice The balance approvals
    /// @dev Owner => Operator => Approved
    mapping(address => mapping(address => bool)) internal operatorApprovals;

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Initializes an ERC-721 token
    /// @param _name The ERC-721 token name
    /// @param _symbol The ERC-721 token symbol
    function __ERC721_init(string memory _name, string memory _symbol) internal onlyInitializing {
        name = _name;
        symbol = _symbol;
    }

    /// @notice The token URI
    /// @param _tokenId The ERC-721 token id
    function tokenURI(uint256 _tokenId) public view virtual returns (string memory) {}

    /// @notice The contract URI
    function contractURI() public view virtual returns (string memory) {}

    /// @notice If the contract implements an interface
    /// @param _interfaceId The interface id
    function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
        return
            _interfaceId == 0x01ffc9a7 || // ERC165 Interface ID
            _interfaceId == 0x80ac58cd || // ERC721 Interface ID
            _interfaceId == 0x5b5e139f; // ERC721Metadata Interface ID
    }

    /// @notice The account approved to manage a token
    /// @param _tokenId The ERC-721 token id
    function getApproved(uint256 _tokenId) external view returns (address) {
        return tokenApprovals[_tokenId];
    }

    /// @notice If an operator is authorized to manage all of an owner's tokens
    /// @param _owner The owner address
    /// @param _operator The operator address
    function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
        return operatorApprovals[_owner][_operator];
    }

    /// @notice The number of tokens owned
    /// @param _owner The owner address
    function balanceOf(address _owner) public view returns (uint256) {
        if (_owner == address(0)) revert ADDRESS_ZERO();

        return balances[_owner];
    }

    /// @notice The owner of a token
    /// @param _tokenId The ERC-721 token id
    function ownerOf(uint256 _tokenId) public view returns (address) {
        address owner = owners[_tokenId];

        if (owner == address(0)) revert INVALID_OWNER();

        return owner;
    }

    /// @notice Authorizes an account to manage a token
    /// @param _to The account address
    /// @param _tokenId The ERC-721 token id
    function approve(address _to, uint256 _tokenId) external {
        address owner = owners[_tokenId];

        if (msg.sender != owner && !operatorApprovals[owner][msg.sender]) revert INVALID_APPROVAL();

        tokenApprovals[_tokenId] = _to;

        emit Approval(owner, _to, _tokenId);
    }

    /// @notice Authorizes an account to manage all tokens
    /// @param _operator The account address
    /// @param _approved If permission is being given or removed
    function setApprovalForAll(address _operator, bool _approved) external {
        operatorApprovals[msg.sender][_operator] = _approved;

        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    /// @notice Transfers a token from sender to recipient
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function transferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) public {
        if (_from != owners[_tokenId]) revert INVALID_OWNER();

        if (_to == address(0)) revert ADDRESS_ZERO();

        if (msg.sender != _from && !operatorApprovals[_from][msg.sender] && msg.sender != tokenApprovals[_tokenId]) revert INVALID_APPROVAL();

        _beforeTokenTransfer(_from, _to, _tokenId);

        unchecked {
            --balances[_from];

            ++balances[_to];
        }

        owners[_tokenId] = _to;

        delete tokenApprovals[_tokenId];

        emit Transfer(_from, _to, _tokenId);

        _afterTokenTransfer(_from, _to, _tokenId);
    }

    /// @notice Safe transfers a token from sender to recipient
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) external {
        transferFrom(_from, _to, _tokenId);

        if (
            Address.isContract(_to) &&
            ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, "") != ERC721TokenReceiver.onERC721Received.selector
        ) revert INVALID_RECIPIENT();
    }

    /// @notice Safe transfers a token from sender to recipient with additional data
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes calldata _data
    ) external {
        transferFrom(_from, _to, _tokenId);

        if (
            Address.isContract(_to) &&
            ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) != ERC721TokenReceiver.onERC721Received.selector
        ) revert INVALID_RECIPIENT();
    }

    /// @dev Mints a token to a recipient
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function _mint(address _to, uint256 _tokenId) internal virtual {
        if (_to == address(0)) revert ADDRESS_ZERO();

        if (owners[_tokenId] != address(0)) revert ALREADY_MINTED();

        _beforeTokenTransfer(address(0), _to, _tokenId);

        unchecked {
            ++balances[_to];
        }

        owners[_tokenId] = _to;

        emit Transfer(address(0), _to, _tokenId);

        _afterTokenTransfer(address(0), _to, _tokenId);
    }

    /// @dev Burns a token to a recipient
    /// @param _tokenId The ERC-721 token id
    function _burn(uint256 _tokenId) internal virtual {
        address owner = owners[_tokenId];

        if (owner == address(0)) revert NOT_MINTED();

        _beforeTokenTransfer(owner, address(0), _tokenId);

        unchecked {
            --balances[owner];
        }

        delete owners[_tokenId];

        delete tokenApprovals[_tokenId];

        emit Transfer(owner, address(0), _tokenId);

        _afterTokenTransfer(owner, address(0), _tokenId);
    }

    /// @dev Hook called before a token transfer
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function _beforeTokenTransfer(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal virtual {}

    /// @dev Hook called after a token transfer
    /// @param _from The sender address
    /// @param _to The recipient address
    /// @param _tokenId The ERC-721 token id
    function _afterTokenTransfer(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal virtual {}
}

File 17 of 28 : ERC721Votes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IERC721Votes } from "../interfaces/IERC721Votes.sol";
import { ERC721 } from "../token/ERC721.sol";
import { EIP712 } from "../utils/EIP712.sol";

/// @title ERC721Votes
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/extensions/draft-ERC721Votes.sol) & Nouns DAO ERC721Checkpointable.sol commit 2cbe6c7 - licensed under the BSD-3-Clause license.
/// - Uses custom errors defined in IERC721Votes
/// - Checkpoints are based on timestamps instead of block numbers
/// - Tokens are self-delegated by default
/// - The total number of votes is the token supply itself
abstract contract ERC721Votes is IERC721Votes, EIP712, ERC721 {
    ///                                                          ///
    ///                          CONSTANTS                       ///
    ///                                                          ///

    /// @dev The EIP-712 typehash to delegate with a signature
    bytes32 internal constant DELEGATION_TYPEHASH = keccak256("Delegation(address from,address to,uint256 nonce,uint256 deadline)");

    ///                                                          ///
    ///                           STORAGE                        ///
    ///                                                          ///

    /// @notice The delegate for an account
    /// @notice Account => Delegate
    mapping(address => address) internal delegation;

    /// @notice The number of checkpoints for an account
    /// @dev Account => Num Checkpoints
    mapping(address => uint256) internal numCheckpoints;

    /// @notice The checkpoint for an account
    /// @dev Account => Checkpoint Id => Checkpoint
    mapping(address => mapping(uint256 => Checkpoint)) internal checkpoints;

    ///                                                          ///
    ///                        VOTING WEIGHT                     ///
    ///                                                          ///

    /// @notice The current number of votes for an account
    /// @param _account The account address
    function getVotes(address _account) public view returns (uint256) {
        // Get the account's number of checkpoints
        uint256 nCheckpoints = numCheckpoints[_account];

        // Cannot underflow as `nCheckpoints` is ensured to be greater than 0 if reached
        unchecked {
            // Return the number of votes at the latest checkpoint if applicable
            return nCheckpoints != 0 ? checkpoints[_account][nCheckpoints - 1].votes : 0;
        }
    }

    /// @notice The number of votes for an account at a past timestamp
    /// @param _account The account address
    /// @param _timestamp The past timestamp
    function getPastVotes(address _account, uint256 _timestamp) public view returns (uint256) {
        // Ensure the given timestamp is in the past
        if (_timestamp >= block.timestamp) revert INVALID_TIMESTAMP();

        // Get the account's number of checkpoints
        uint256 nCheckpoints = numCheckpoints[_account];

        // If there are none return 0
        if (nCheckpoints == 0) return 0;

        // Get the account's checkpoints
        mapping(uint256 => Checkpoint) storage accountCheckpoints = checkpoints[_account];

        unchecked {
            // Get the latest checkpoint id
            // Cannot underflow as `nCheckpoints` is ensured to be greater than 0
            uint256 lastCheckpoint = nCheckpoints - 1;

            // If the latest checkpoint has a valid timestamp, return its number of votes
            if (accountCheckpoints[lastCheckpoint].timestamp <= _timestamp) return accountCheckpoints[lastCheckpoint].votes;

            // If the first checkpoint doesn't have a valid timestamp, return 0
            if (accountCheckpoints[0].timestamp > _timestamp) return 0;

            // Otherwise, find a checkpoint with a valid timestamp
            // Use the latest id as the initial upper bound
            uint256 high = lastCheckpoint;
            uint256 low;
            uint256 middle;

            // Used to temporarily hold a checkpoint
            Checkpoint memory cp;

            // While a valid checkpoint is to be found:
            while (high > low) {
                // Find the id of the middle checkpoint
                middle = high - (high - low) / 2;

                // Get the middle checkpoint
                cp = accountCheckpoints[middle];

                // If the timestamp is a match:
                if (cp.timestamp == _timestamp) {
                    // Return the voting weight
                    return cp.votes;

                    // Else if the timestamp is before the one looking for:
                } else if (cp.timestamp < _timestamp) {
                    // Update the lower bound
                    low = middle;

                    // Else update the upper bound
                } else {
                    high = middle - 1;
                }
            }

            return accountCheckpoints[low].votes;
        }
    }

    ///                                                          ///
    ///                          DELEGATION                      ///
    ///                                                          ///

    /// @notice The delegate for an account
    /// @param _account The account address
    function delegates(address _account) public view returns (address) {
        address current = delegation[_account];
        return current == address(0) ? _account : current;
    }

    /// @notice Delegates votes to an account
    /// @param _to The address delegating votes to
    function delegate(address _to) external {
        _delegate(msg.sender, _to);
    }

    /// @notice Delegates votes from a signer to an account
    /// @param _from The address delegating votes from
    /// @param _to The address delegating votes to
    /// @param _deadline The signature deadline
    /// @param _v The 129th byte and chain id of the signature
    /// @param _r The first 64 bytes of the signature
    /// @param _s Bytes 64-128 of the signature
    function delegateBySig(
        address _from,
        address _to,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external {
        // Ensure the signature has not expired
        if (block.timestamp > _deadline) revert EXPIRED_SIGNATURE();

        // Used to store the digest
        bytes32 digest;

        // Cannot realistically overflow
        unchecked {
            // Compute the hash of the domain seperator with the typed delegation data
            digest = keccak256(
                abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(DELEGATION_TYPEHASH, _from, _to, nonces[_from]++, _deadline)))
            );
        }

        // Recover the message signer
        address recoveredAddress = ecrecover(digest, _v, _r, _s);

        // Ensure the recovered signer is the voter
        if (recoveredAddress == address(0) || recoveredAddress != _from) revert INVALID_SIGNATURE();

        // Update the delegate
        _delegate(_from, _to);
    }

    /// @dev Updates delegate addresses
    /// @param _from The address delegating votes from
    /// @param _to The address delegating votes to
    function _delegate(address _from, address _to) internal {
        // If address(0) is being delegated to, update the op as a self-delegate
        if (_to == address(0)) _to = _from;

        // Get the previous delegate
        address prevDelegate = delegates(_from);

        // Store the new delegate
        delegation[_from] = _to;

        emit DelegateChanged(_from, prevDelegate, _to);

        // Transfer voting weight from the previous delegate to the new delegate
        _moveDelegateVotes(prevDelegate, _to, balanceOf(_from));
    }

    /// @dev Transfers voting weight
    /// @param _from The address delegating votes from
    /// @param _to The address delegating votes to
    /// @param _amount The number of votes delegating
    function _moveDelegateVotes(
        address _from,
        address _to,
        uint256 _amount
    ) internal {
        unchecked {
            // If voting weight is being transferred:
            if (_from != _to && _amount > 0) {
                // If this isn't a token mint:
                if (_from != address(0)) {
                    // Get the sender's number of checkpoints
                    uint256 newCheckpointId = numCheckpoints[_from];

                    // Used to store their previous checkpoint id
                    uint256 prevCheckpointId;

                    // Used to store their previous checkpoint's voting weight
                    uint256 prevTotalVotes;

                    // Used to store their previous checkpoint's timestamp
                    uint256 prevTimestamp;

                    // If this isn't the sender's first checkpoint:
                    if (newCheckpointId != 0) {
                        // Get their previous checkpoint's id
                        prevCheckpointId = newCheckpointId - 1;

                        // Get their previous checkpoint's voting weight
                        prevTotalVotes = checkpoints[_from][prevCheckpointId].votes;

                        // Get their previous checkpoint's timestamp
                        prevTimestamp = checkpoints[_from][prevCheckpointId].timestamp;
                    }

                    // Update their voting weight
                    _writeCheckpoint(_from, newCheckpointId, prevCheckpointId, prevTimestamp, prevTotalVotes, prevTotalVotes - _amount);
                }

                // If this isn't a token burn:
                if (_to != address(0)) {
                    // Get the recipients's number of checkpoints
                    uint256 nCheckpoints = numCheckpoints[_to];

                    // Used to store their previous checkpoint id
                    uint256 prevCheckpointId;

                    // Used to store their previous checkpoint's voting weight
                    uint256 prevTotalVotes;

                    // Used to store their previous checkpoint's timestamp
                    uint256 prevTimestamp;

                    // If this isn't the recipient's first checkpoint:
                    if (nCheckpoints != 0) {
                        // Get their previous checkpoint's id
                        prevCheckpointId = nCheckpoints - 1;

                        // Get their previous checkpoint's voting weight
                        prevTotalVotes = checkpoints[_to][prevCheckpointId].votes;

                        // Get their previous checkpoint's timestamp
                        prevTimestamp = checkpoints[_to][prevCheckpointId].timestamp;
                    }

                    // Update their voting weight
                    _writeCheckpoint(_to, nCheckpoints, prevCheckpointId, prevTimestamp, prevTotalVotes, prevTotalVotes + _amount);
                }
            }
        }
    }

    /// @dev Records a checkpoint
    /// @param _account The account address
    /// @param _newId The new checkpoint id
    /// @param _prevId The previous checkpoint id
    /// @param _prevTimestamp The previous checkpoint timestamp
    /// @param _prevTotalVotes The previous checkpoint voting weight
    /// @param _newTotalVotes The new checkpoint voting weight
    function _writeCheckpoint(
        address _account,
        uint256 _newId,
        uint256 _prevId,
        uint256 _prevTimestamp,
        uint256 _prevTotalVotes,
        uint256 _newTotalVotes
    ) private {
        unchecked {
            // If the new checkpoint is not the user's first AND has the timestamp of the previous checkpoint:
            if (_newId > 0 && _prevTimestamp == block.timestamp) {
                // Just update the previous checkpoint's votes
                checkpoints[_account][_prevId].votes = uint192(_newTotalVotes);

                // Else write a new checkpoint:
            } else {
                // Get the pointer to store the checkpoint
                Checkpoint storage checkpoint = checkpoints[_account][_newId];

                // Store the new voting weight and the current time
                checkpoint.votes = uint192(_newTotalVotes);
                checkpoint.timestamp = uint64(block.timestamp);

                // Increment the account's number of checkpoints
                ++numCheckpoints[_account];
            }

            emit DelegateVotesChanged(_account, _prevTotalVotes, _newTotalVotes);
        }
    }

    /// @dev Enables each NFT to equal 1 vote
    /// @param _from The token sender
    /// @param _to The token recipient
    /// @param _tokenId The ERC-721 token id
    function _afterTokenTransfer(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal override {
        // Transfer 1 vote from the sender to the recipient
        _moveDelegateVotes(delegates(_from), delegates(_to), 1);

        super._afterTokenTransfer(_from, _to, _tokenId);
    }
}

File 18 of 28 : Address.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title EIP712
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (utils/Address.sol)
/// - Uses custom errors `INVALID_TARGET()` & `DELEGATE_CALL_FAILED()`
/// - Adds util converting address to bytes32
library Address {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the target of a delegatecall is not a contract
    error INVALID_TARGET();

    /// @dev Reverts if a delegatecall has failed
    error DELEGATE_CALL_FAILED();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Utility to convert an address to bytes32
    function toBytes32(address _account) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(_account)) << 96);
    }

    /// @dev If an address is a contract
    function isContract(address _account) internal view returns (bool rv) {
        assembly {
            rv := gt(extcodesize(_account), 0)
        }
    }

    /// @dev Performs a delegatecall on an address
    function functionDelegateCall(address _target, bytes memory _data) internal returns (bytes memory) {
        if (!isContract(_target)) revert INVALID_TARGET();

        (bool success, bytes memory returndata) = _target.delegatecall(_data);

        return verifyCallResult(success, returndata);
    }

    /// @dev Verifies a delegatecall was successful
    function verifyCallResult(bool _success, bytes memory _returndata) internal pure returns (bytes memory) {
        if (_success) {
            return _returndata;
        } else {
            if (_returndata.length > 0) {
                assembly {
                    let returndata_size := mload(_returndata)

                    revert(add(32, _returndata), returndata_size)
                }
            } else {
                revert DELEGATE_CALL_FAILED();
            }
        }
    }
}

File 19 of 28 : EIP712.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IEIP712 } from "../interfaces/IEIP712.sol";
import { Initializable } from "../utils/Initializable.sol";

/// @title EIP712
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (utils/cryptography/draft-EIP712Upgradeable.sol)
/// - Uses custom errors declared in IEIP712
/// - Caches `INITIAL_CHAIN_ID` and `INITIAL_DOMAIN_SEPARATOR` upon initialization
/// - Adds mapping for account nonces
abstract contract EIP712 is IEIP712, Initializable {
    ///                                                          ///
    ///                          CONSTANTS                       ///
    ///                                                          ///

    /// @dev The EIP-712 domain typehash
    bytes32 internal constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    ///                                                          ///
    ///                           STORAGE                        ///
    ///                                                          ///

    /// @notice The hash of the EIP-712 domain name
    bytes32 internal HASHED_NAME;

    /// @notice The hash of the EIP-712 domain version
    bytes32 internal HASHED_VERSION;

    /// @notice The domain separator computed upon initialization
    bytes32 internal INITIAL_DOMAIN_SEPARATOR;

    /// @notice The chain id upon initialization
    uint256 internal INITIAL_CHAIN_ID;

    /// @notice The account nonces
    /// @dev Account => Nonce
    mapping(address => uint256) internal nonces;

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Initializes EIP-712 support
    /// @param _name The EIP-712 domain name
    /// @param _version The EIP-712 domain version
    function __EIP712_init(string memory _name, string memory _version) internal onlyInitializing {
        HASHED_NAME = keccak256(bytes(_name));
        HASHED_VERSION = keccak256(bytes(_version));

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
    }

    /// @notice The current nonce for an account
    /// @param _account The account address
    function nonce(address _account) external view returns (uint256) {
        return nonces[_account];
    }

    /// @notice The EIP-712 domain separator
    function DOMAIN_SEPARATOR() public view returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();
    }

    /// @dev Computes the EIP-712 domain separator
    function _computeDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(DOMAIN_TYPEHASH, HASHED_NAME, HASHED_VERSION, block.chainid, address(this)));
    }
}

File 20 of 28 : Initializable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IInitializable } from "../interfaces/IInitializable.sol";
import { Address } from "../utils/Address.sol";

/// @title Initializable
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/utils/Initializable.sol)
/// - Uses custom errors declared in IInitializable
abstract contract Initializable is IInitializable {
    ///                                                          ///
    ///                           STORAGE                        ///
    ///                                                          ///

    /// @dev Indicates the contract has been initialized
    uint8 internal _initialized;

    /// @dev Indicates the contract is being initialized
    bool internal _initializing;

    ///                                                          ///
    ///                          MODIFIERS                       ///
    ///                                                          ///

    /// @dev Ensures an initialization function is only called within an `initializer` or `reinitializer` function
    modifier onlyInitializing() {
        if (!_initializing) revert NOT_INITIALIZING();
        _;
    }

    /// @dev Enables initializing upgradeable contracts
    modifier initializer() {
        bool isTopLevelCall = !_initializing;

        if ((!isTopLevelCall || _initialized != 0) && (Address.isContract(address(this)) || _initialized != 1)) revert ALREADY_INITIALIZED();

        _initialized = 1;

        if (isTopLevelCall) {
            _initializing = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;

            emit Initialized(1);
        }
    }

    /// @dev Enables initializer versioning
    /// @param _version The version to set
    modifier reinitializer(uint8 _version) {
        if (_initializing || _initialized >= _version) revert ALREADY_INITIALIZED();

        _initialized = _version;

        _initializing = true;

        _;

        _initializing = false;

        emit Initialized(_version);
    }

    ///                                                          ///
    ///                          FUNCTIONS                       ///
    ///                                                          ///

    /// @dev Prevents future initialization
    function _disableInitializers() internal virtual {
        if (_initializing) revert INITIALIZING();

        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;

            emit Initialized(type(uint8).max);
        }
    }
}

File 21 of 28 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IOwnable } from "../interfaces/IOwnable.sol";
import { Initializable } from "../utils/Initializable.sol";

/// @title Ownable
/// @author Rohan Kulkarni
/// @notice Modified from OpenZeppelin Contracts v4.7.3 (access/OwnableUpgradeable.sol)
/// - Uses custom errors declared in IOwnable
/// - Adds optional two-step ownership transfer (`safeTransferOwnership` + `acceptOwnership`)
abstract contract Ownable is IOwnable, Initializable {
    ///                                                          ///
    ///                            STORAGE                       ///
    ///                                                          ///

    /// @dev The address of the owner
    address internal _owner;

    /// @dev The address of the pending owner
    address internal _pendingOwner;

    ///                                                          ///
    ///                           MODIFIERS                      ///
    ///                                                          ///

    /// @dev Ensures the caller is the owner
    modifier onlyOwner() {
        if (msg.sender != _owner) revert ONLY_OWNER();
        _;
    }

    /// @dev Ensures the caller is the pending owner
    modifier onlyPendingOwner() {
        if (msg.sender != _pendingOwner) revert ONLY_PENDING_OWNER();
        _;
    }

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Initializes contract ownership
    /// @param _initialOwner The initial owner address
    function __Ownable_init(address _initialOwner) internal onlyInitializing {
        _owner = _initialOwner;

        emit OwnerUpdated(address(0), _initialOwner);
    }

    /// @notice The address of the owner
    function owner() public virtual view returns (address) {
        return _owner;
    }

    /// @notice The address of the pending owner
    function pendingOwner() public view returns (address) {
        return _pendingOwner;
    }

    /// @notice Forces an ownership transfer from the last owner
    /// @param _newOwner The new owner address
    function transferOwnership(address _newOwner) public onlyOwner {
        _transferOwnership(_newOwner);
    }

    /// @notice Forces an ownership transfer from any sender
    /// @param _newOwner New owner to transfer contract to
    /// @dev Ensure is called only from trusted internal code, no access control checks.
    function _transferOwnership(address _newOwner) internal {
        emit OwnerUpdated(_owner, _newOwner);

        _owner = _newOwner;

        if (_pendingOwner != address(0)) delete _pendingOwner;
    }

    /// @notice Initiates a two-step ownership transfer
    /// @param _newOwner The new owner address
    function safeTransferOwnership(address _newOwner) public onlyOwner {
        _pendingOwner = _newOwner;

        emit OwnerPending(_owner, _newOwner);
    }

    /// @notice Accepts an ownership transfer
    function acceptOwnership() public onlyPendingOwner {
        emit OwnerUpdated(_owner, msg.sender);

        _owner = _pendingOwner;

        delete _pendingOwner;
    }

    /// @notice Cancels a pending ownership transfer
    function cancelOwnershipTransfer() public onlyOwner {
        emit OwnerCanceled(_owner, _pendingOwner);

        delete _pendingOwner;
    }
}

File 22 of 28 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

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

/// @notice Modified from OpenZeppelin Contracts v4.7.3 (security/ReentrancyGuardUpgradeable.sol)
/// - Uses custom error `REENTRANCY()`
abstract contract ReentrancyGuard is Initializable {
    ///                                                          ///
    ///                            STORAGE                       ///
    ///                                                          ///

    /// @dev Indicates a function has not been entered
    uint256 internal constant _NOT_ENTERED = 1;

    /// @dev Indicates a function has been entered
    uint256 internal constant _ENTERED = 2;

    /// @notice The reentrancy status of a function
    uint256 internal _status;

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if attempted reentrancy
    error REENTRANCY();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @dev Initializes the reentrancy guard
    function __ReentrancyGuard_init() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /// @dev Ensures a function cannot be reentered
    modifier nonReentrant() {
        if (_status == _ENTERED) revert REENTRANCY();

        _status = _ENTERED;

        _;

        _status = _NOT_ENTERED;
    }
}

File 23 of 28 : TokenReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/utils/ERC721Holder.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

/// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC1155/utils/ERC1155Holder.sol)
abstract contract ERC1155TokenReceiver {
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) external virtual returns (bytes4) {
        return this.onERC1155BatchReceived.selector;
    }
}

File 24 of 28 : IManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../lib/interfaces/IUUPS.sol";
import { IOwnable } from "../lib/interfaces/IOwnable.sol";

/// @title IManager
/// @author Rohan Kulkarni
/// @notice The external Manager events, errors, structs and functions
interface IManager is IUUPS, IOwnable {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a DAO is deployed
    /// @param token The ERC-721 token address
    /// @param metadata The metadata renderer address
    /// @param auction The auction address
    /// @param treasury The treasury address
    /// @param governor The governor address
    event DAODeployed(address token, address metadata, address auction, address treasury, address governor);

    /// @notice Emitted when an upgrade is registered by the Builder DAO
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    event UpgradeRegistered(address baseImpl, address upgradeImpl);

    /// @notice Emitted when an upgrade is unregistered by the Builder DAO
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    event UpgradeRemoved(address baseImpl, address upgradeImpl);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if at least one founder is not provided upon deploy
    error FOUNDER_REQUIRED();

    ///                                                          ///
    ///                            STRUCTS                       ///
    ///                                                          ///

    /// @notice The founder parameters
    /// @param wallet The wallet address
    /// @param ownershipPct The percent ownership of the token
    /// @param vestExpiry The timestamp that vesting expires
    struct FounderParams {
        address wallet;
        uint256 ownershipPct;
        uint256 vestExpiry;
    }

    /// @notice DAO Version Information information struct
    struct DAOVersionInfo {
        string token;
        string metadata;
        string auction;
        string treasury;
        string governor; 
    }

    /// @notice The ERC-721 token parameters
    /// @param initStrings The encoded token name, symbol, collection description, collection image uri, renderer base uri
    struct TokenParams {
        bytes initStrings;
    }

    /// @notice The auction parameters
    /// @param reservePrice The reserve price of each auction
    /// @param duration The duration of each auction
    struct AuctionParams {
        uint256 reservePrice;
        uint256 duration;
    }

    /// @notice The governance parameters
    /// @param timelockDelay The time delay to execute a queued transaction
    /// @param votingDelay The time delay to vote on a created proposal
    /// @param votingPeriod The time period to vote on a proposal
    /// @param proposalThresholdBps The basis points of the token supply required to create a proposal
    /// @param quorumThresholdBps The basis points of the token supply required to reach quorum
    /// @param vetoer The address authorized to veto proposals (address(0) if none desired)
    struct GovParams {
        uint256 timelockDelay;
        uint256 votingDelay;
        uint256 votingPeriod;
        uint256 proposalThresholdBps;
        uint256 quorumThresholdBps;
        address vetoer;
    }

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice The token implementation address
    function tokenImpl() external view returns (address);

    /// @notice The metadata renderer implementation address
    function metadataImpl() external view returns (address);

    /// @notice The auction house implementation address
    function auctionImpl() external view returns (address);

    /// @notice The treasury implementation address
    function treasuryImpl() external view returns (address);

    /// @notice The governor implementation address
    function governorImpl() external view returns (address);

    /// @notice Deploys a DAO with custom token, auction, and governance settings
    /// @param founderParams The DAO founder(s)
    /// @param tokenParams The ERC-721 token settings
    /// @param auctionParams The auction settings
    /// @param govParams The governance settings
    function deploy(
        FounderParams[] calldata founderParams,
        TokenParams calldata tokenParams,
        AuctionParams calldata auctionParams,
        GovParams calldata govParams
    )
        external
        returns (
            address token,
            address metadataRenderer,
            address auction,
            address treasury,
            address governor
        );

    /// @notice A DAO's remaining contract addresses from its token address
    /// @param token The ERC-721 token address
    function getAddresses(address token)
        external
        returns (
            address metadataRenderer,
            address auction,
            address treasury,
            address governor
        );

    /// @notice If an implementation is registered by the Builder DAO as an optional upgrade
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    function isRegisteredUpgrade(address baseImpl, address upgradeImpl) external view returns (bool);

    /// @notice Called by the Builder DAO to offer opt-in implementation upgrades for all other DAOs
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    function registerUpgrade(address baseImpl, address upgradeImpl) external;

    /// @notice Called by the Builder DAO to remove an upgrade
    /// @param baseImpl The base implementation address
    /// @param upgradeImpl The upgrade implementation address
    function removeUpgrade(address baseImpl, address upgradeImpl) external;
}

File 25 of 28 : IToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../lib/interfaces/IUUPS.sol";
import { IERC721Votes } from "../lib/interfaces/IERC721Votes.sol";
import { IManager } from "../manager/IManager.sol";
import { TokenTypesV1 } from "./types/TokenTypesV1.sol";

/// @title IToken
/// @author Rohan Kulkarni
/// @notice The external Token events, errors and functions
interface IToken is IUUPS, IERC721Votes, TokenTypesV1 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a token is scheduled to be allocated
    /// @param baseTokenId The
    /// @param founderId The founder's id
    /// @param founder The founder's vesting details
    event MintScheduled(uint256 baseTokenId, uint256 founderId, Founder founder);

    /// @notice Emitted when a token allocation is unscheduled (removed)
    /// @param baseTokenId The token ID % 100
    /// @param founderId The founder's id
    /// @param founder The founder's vesting details
    event MintUnscheduled(uint256 baseTokenId, uint256 founderId, Founder founder);

    /// @notice Emitted when a tokens founders are deleted from storage
    /// @param newFounders the list of founders
    event FounderAllocationsCleared(IManager.FounderParams[] newFounders);

    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the founder ownership exceeds 100 percent
    error INVALID_FOUNDER_OWNERSHIP();

    /// @dev Reverts if the caller was not the auction contract
    error ONLY_AUCTION();

    /// @dev Reverts if no metadata was generated upon mint
    error NO_METADATA_GENERATED();

    /// @dev Reverts if the caller was not the contract manager
    error ONLY_MANAGER();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice Initializes a DAO's ERC-721 token
    /// @param founders The founding members to receive vesting allocations
    /// @param initStrings The encoded token and metadata initialization strings
    /// @param metadataRenderer The token's metadata renderer
    /// @param auction The token's auction house
    function initialize(
        IManager.FounderParams[] calldata founders,
        bytes calldata initStrings,
        address metadataRenderer,
        address auction,
        address initialOwner
    ) external;

    /// @notice Mints tokens to the auction house for bidding and handles founder vesting
    function mint() external returns (uint256 tokenId);

    /// @notice Burns a token that did not see any bids
    /// @param tokenId The ERC-721 token id
    function burn(uint256 tokenId) external;

    /// @notice The URI for a token
    /// @param tokenId The ERC-721 token id
    function tokenURI(uint256 tokenId) external view returns (string memory);

    /// @notice The URI for the contract
    function contractURI() external view returns (string memory);

    /// @notice The number of founders
    function totalFounders() external view returns (uint256);

    /// @notice The founders total percent ownership
    function totalFounderOwnership() external view returns (uint256);

    /// @notice The vesting details of a founder
    /// @param founderId The founder id
    function getFounder(uint256 founderId) external view returns (Founder memory);

    /// @notice The vesting details of all founders
    function getFounders() external view returns (Founder[] memory);

    /// @notice Update the list of allocation owners
    /// @param newFounders the full list of FounderParam structs
    function updateFounders(IManager.FounderParams[] calldata newFounders) external;                                                         
       

    /// @notice The founder scheduled to receive the given token id
    /// NOTE: If a founder is returned, there's no guarantee they'll receive the token as vesting expiration is not considered
    /// @param tokenId The ERC-721 token id
    function getScheduledRecipient(uint256 tokenId) external view returns (Founder memory);

    /// @notice The total supply of tokens
    function totalSupply() external view returns (uint256);

    /// @notice The token's auction house
    function auction() external view returns (address);

    /// @notice The token's metadata renderer
    function metadataRenderer() external view returns (address);

    /// @notice The owner of the token and metadata renderer
    function owner() external view returns (address);

    /// @notice Callback called by auction on first auction started to transfer ownership to treasury from founder
    function onFirstAuctionStarted() external;
}

File 26 of 28 : IBaseMetadata.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IUUPS } from "../../../lib/interfaces/IUUPS.sol";


/// @title IBaseMetadata
/// @author Rohan Kulkarni
/// @notice The external Base Metadata errors and functions
interface IBaseMetadata is IUUPS {
    ///                                                          ///
    ///                            ERRORS                        ///
    ///                                                          ///

    /// @dev Reverts if the caller was not the contract manager
    error ONLY_MANAGER();

    ///                                                          ///
    ///                           FUNCTIONS                      ///
    ///                                                          ///

    /// @notice Initializes a DAO's token metadata renderer
    /// @param initStrings The encoded token and metadata initialization strings
    /// @param token The associated ERC-721 token address
    function initialize(
        bytes calldata initStrings,
        address token
    ) external;

    /// @notice Generates attributes for a token upon mint
    /// @param tokenId The ERC-721 token id
    function onMinted(uint256 tokenId) external returns (bool);

    /// @notice The token URI
    /// @param tokenId The ERC-721 token id
    function tokenURI(uint256 tokenId) external view returns (string memory);

    /// @notice The contract URI
    function contractURI() external view returns (string memory);

    /// @notice The associated ERC-721 token
    function token() external view returns (address);

    /// @notice Get metadata owner address
    function owner() external view returns (address);
}

File 27 of 28 : TokenStorageV1.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { TokenTypesV1 } from "../types/TokenTypesV1.sol";

/// @title TokenStorageV1
/// @author Rohan Kulkarni
/// @notice The Token storage contract
contract TokenStorageV1 is TokenTypesV1 {
    /// @notice The token settings
    Settings internal settings;

    /// @notice The vesting details of a founder
    /// @dev Founder id => Founder
    mapping(uint256 => Founder) internal founder;

    /// @notice The recipient of a token
    /// @dev ERC-721 token id => Founder
    mapping(uint256 => Founder) internal tokenRecipient;
}

File 28 of 28 : TokenTypesV1.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { IBaseMetadata } from "../metadata/interfaces/IBaseMetadata.sol";

/// @title TokenTypesV1
/// @author Rohan Kulkarni
/// @notice The Token custom data types
interface TokenTypesV1 {
    /// @notice The settings type
    /// @param auction The DAO auction house
    /// @param totalSupply The number of active tokens
    /// @param numFounders The number of vesting recipients
    /// @param metadatarenderer The token metadata renderer
    /// @param mintCount The number of minted tokens
    /// @param totalPercentage The total percentage owned by founders
    struct Settings {
        address auction;
        uint88 totalSupply;
        uint8 numFounders;
        IBaseMetadata metadataRenderer;
        uint88 mintCount;
        uint8 totalOwnership;
    }

    /// @notice The founder type
    /// @param wallet The address where tokens are sent
    /// @param ownershipPct The percentage of token ownership
    /// @param vestExpiry The timestamp when vesting ends
    struct Founder {
        address wallet;
        uint8 ownershipPct;
        uint32 vestExpiry;
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/=node_modules/@openzeppelin/",
    "ds-test/=node_modules/ds-test/src/",
    "forge-std/=node_modules/forge-std/src/",
    "micro-onchain-metadata-utils/=node_modules/micro-onchain-metadata-utils/src/",
    "sol-uriencode/=node_modules/sol-uriencode/",
    "sol2string/=node_modules/sol2string/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 500000
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"ADDRESS_ZERO","type":"error"},{"inputs":[],"name":"ALREADY_INITIALIZED","type":"error"},{"inputs":[],"name":"ALREADY_MINTED","type":"error"},{"inputs":[],"name":"DELEGATE_CALL_FAILED","type":"error"},{"inputs":[],"name":"EXPIRED_SIGNATURE","type":"error"},{"inputs":[],"name":"INITIALIZING","type":"error"},{"inputs":[],"name":"INVALID_APPROVAL","type":"error"},{"inputs":[],"name":"INVALID_FOUNDER_OWNERSHIP","type":"error"},{"inputs":[],"name":"INVALID_OWNER","type":"error"},{"inputs":[],"name":"INVALID_RECIPIENT","type":"error"},{"inputs":[],"name":"INVALID_SIGNATURE","type":"error"},{"inputs":[],"name":"INVALID_TARGET","type":"error"},{"inputs":[],"name":"INVALID_TIMESTAMP","type":"error"},{"inputs":[{"internalType":"address","name":"impl","type":"address"}],"name":"INVALID_UPGRADE","type":"error"},{"inputs":[],"name":"NOT_INITIALIZING","type":"error"},{"inputs":[],"name":"NOT_MINTED","type":"error"},{"inputs":[],"name":"NO_METADATA_GENERATED","type":"error"},{"inputs":[],"name":"ONLY_AUCTION","type":"error"},{"inputs":[],"name":"ONLY_CALL","type":"error"},{"inputs":[],"name":"ONLY_DELEGATECALL","type":"error"},{"inputs":[],"name":"ONLY_MANAGER","type":"error"},{"inputs":[],"name":"ONLY_OWNER","type":"error"},{"inputs":[],"name":"ONLY_PENDING_OWNER","type":"error"},{"inputs":[],"name":"ONLY_PROXY","type":"error"},{"inputs":[],"name":"ONLY_UUPS","type":"error"},{"inputs":[],"name":"REENTRANCY","type":"error"},{"inputs":[],"name":"UNSUPPORTED_UUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"prevTotalVotes","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalVotes","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"ownershipPct","type":"uint256"},{"internalType":"uint256","name":"vestExpiry","type":"uint256"}],"indexed":false,"internalType":"struct IManager.FounderParams[]","name":"newFounders","type":"tuple[]"}],"name":"FounderAllocationsCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"founderId","type":"uint256"},{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"indexed":false,"internalType":"struct TokenTypesV1.Founder","name":"founder","type":"tuple"}],"name":"MintScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"founderId","type":"uint256"},{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"indexed":false,"internalType":"struct TokenTypesV1.Founder","name":"founder","type":"tuple"}],"name":"MintUnscheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"canceledOwner","type":"address"}],"name":"OwnerCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnerPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"impl","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"auction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_founderId","type":"uint256"}],"name":"getFounder","outputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"internalType":"struct TokenTypesV1.Founder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFounders","outputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"internalType":"struct TokenTypesV1.Founder[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getScheduledRecipient","outputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"internalType":"struct TokenTypesV1.Founder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"ownershipPct","type":"uint256"},{"internalType":"uint256","name":"vestExpiry","type":"uint256"}],"internalType":"struct IManager.FounderParams[]","name":"_founders","type":"tuple[]"},{"internalType":"bytes","name":"_initStrings","type":"bytes"},{"internalType":"address","name":"_metadataRenderer","type":"address"},{"internalType":"address","name":"_auction","type":"address"},{"internalType":"address","name":"_initialOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataRenderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"onFirstAuctionStarted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"safeTransferOwnership","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":"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":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFounderOwnership","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFounders","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"ownershipPct","type":"uint256"},{"internalType":"uint256","name":"vestExpiry","type":"uint256"}],"internalType":"struct IManager.FounderParams[]","name":"newFounders","type":"tuple[]"}],"name":"updateFounders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]

60c060408190523060805262004e2f3881900390819083398101604081905262000029916200011c565b600054610100900460ff161580158062000047575060005460ff1615155b801562000077575062000065306200011660201b62002b3c1760201c565b8062000077575060005460ff16600114155b15620000965760405163439a74c960e01b815260040160405180910390fd5b6000805460ff191660011790558015620000ba576000805461ff0019166101001790555b6001600160a01b03821660a05280156200010e576000805461ff0019169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b50506200014e565b3b151590565b6000602082840312156200012f57600080fd5b81516001600160a01b03811681146200014757600080fd5b9392505050565b60805160a051614c986200019760003960008181611a6f0152612e0201526000818161116a015281816111c401528181611777015281816117d101526118c40152614c986000f3fe6080604052600436106102e75760003560e01c806370a0823111610184578063b20d7fa9116100d6578063d9d3e0901161008a578063e8a3d48511610064578063e8a3d48514610988578063e985e9c51461099d578063f2fde38b146109f357600080fd5b8063d9d3e09014610902578063dc276e571461093d578063e30c39781461095d57600080fd5b8063b88d4fde116100bb578063b88d4fde146108a2578063c87b56dd146108c2578063d1bfda66146108e257600080fd5b8063b20d7fa914610860578063b73cdd191461088057600080fd5b80638da5cb5b116101385780639d8aefc2116101125780639d8aefc2146107e5578063a0a8e460146107fa578063a22cb4651461084057600080fd5b80638da5cb5b1461077f57806395d89b41146107b05780639ab24eb0146107c557600080fd5b806374fd46551161016957806374fd46551461070457806379ba50971461073f5780637d9f6db51461075457600080fd5b806370a08231146106a157806370ae92d2146106c157600080fd5b80633a46b1a81161023d57806352d1902d116101f15780636097bf62116101cb5780636097bf62146106365780636352211e14610656578063703199701461067657600080fd5b806352d1902d146105e1578063587cde1e146105f65780635c19a95c1461061657600080fd5b806342842e0e1161022257806342842e0e1461058e57806342966c68146105ae5780634f1ef286146105ce57600080fd5b80633a46b1a8146104b45780633bcb43f3146104d457600080fd5b806318160ddd1161029f5780633644e515116102795780633644e5151461045f5780633659cfe614610474578063395db2cd1461049457600080fd5b806318160ddd146103f057806323452b9c1461042a57806323b872dd1461043f57600080fd5b8063081812fc116102d0578063081812fc14610343578063095ea7b3146103ab5780631249c58b146103cd57600080fd5b806301ffc9a7146102ec57806306fdde0314610321575b600080fd5b3480156102f857600080fd5b5061030c610307366004614076565b610a13565b60405190151581526020015b60405180910390f35b34801561032d57600080fd5b50610336610af8565b60405161031891906140b7565b34801561034f57600080fd5b5061038661035e366004614108565b6000908152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610318565b3480156103b757600080fd5b506103cb6103c6366004614143565b610b86565b005b3480156103d957600080fd5b506103e2610ca4565b604051908152602001610318565b3480156103fc57600080fd5b506011547401000000000000000000000000000000000000000090046affffffffffffffffffffff166103e2565b34801561043657600080fd5b506103cb610db6565b34801561044b57600080fd5b506103cb61045a36600461416f565b610e88565b34801561046b57600080fd5b506103e26110d0565b34801561048057600080fd5b506103cb61048f3660046141b0565b611153565b3480156104a057600080fd5b506103cb6104af3660046141b0565b6112ab565b3480156104c057600080fd5b506103e26104cf366004614143565b61137f565b3480156104e057600080fd5b506105816104ef366004614108565b6040805160608082018352600080835260208084018290529284018190529384526013825292829020825193840183525473ffffffffffffffffffffffffffffffffffffffff8116845274010000000000000000000000000000000000000000810460ff16918401919091527501000000000000000000000000000000000000000000900463ffffffff169082015290565b60405161031891906141cd565b34801561059a57600080fd5b506103cb6105a936600461416f565b6115e3565b3480156105ba57600080fd5b506103cb6105c9366004614108565b611706565b6103cb6105dc36600461430f565b611760565b3480156105ed57600080fd5b506103e26118aa565b34801561060257600080fd5b506103866106113660046141b0565b611940565b34801561062257600080fd5b506103cb6106313660046141b0565b61197f565b34801561064257600080fd5b506103cb610651366004614401565b611989565b34801561066257600080fd5b50610386610671366004614108565b611bc6565b34801561068257600080fd5b5060125473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156106ad57600080fd5b506103e26106bc3660046141b0565b611c22565b3480156106cd57600080fd5b506103e26106dc3660046141b0565b73ffffffffffffffffffffffffffffffffffffffff1660009081526007602052604090205490565b34801561071057600080fd5b506011547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561074b57600080fd5b506103cb611c9a565b34801561076057600080fd5b5060115473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561078b57600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156107bc57600080fd5b50610336611da4565b3480156107d157600080fd5b506103e26107e03660046141b0565b611db1565b3480156107f157600080fd5b506103cb611e80565b34801561080657600080fd5b5060408051808201909152600581527f312e312e300000000000000000000000000000000000000000000000000000006020820152610336565b34801561084c57600080fd5b506103cb61085b3660046144b8565b611f6f565b34801561086c57600080fd5b506103cb61087b3660046144f1565b612006565b34801561088c57600080fd5b5061089561225b565b604051610318919061455c565b3480156108ae57600080fd5b506103cb6108bd3660046145dd565b6123c5565b3480156108ce57600080fd5b506103366108dd366004614108565b6124dd565b3480156108ee57600080fd5b506103cb6108fd366004614650565b612593565b34801561090e57600080fd5b506012547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561094957600080fd5b50610581610958366004614108565b612978565b34801561096957600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561099457600080fd5b50610336612a26565b3480156109a957600080fd5b5061030c6109b8366004614692565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600d6020908152604080832093909416825291909152205460ff1690565b3480156109ff57600080fd5b506103cb610a0e3660046141b0565b612adc565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610aa657507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610af257507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60088054610b05906146c0565b80601f0160208091040260200160405190810160405280929190818152602001828054610b31906146c0565b8015610b7e5780601f10610b5357610100808354040283529160200191610b7e565b820191906000526020600020905b815481529060010190602001808311610b6157829003601f168201915b505050505081565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114801590610bec575073ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020908152604080832033845290915290205460ff16155b15610c23576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600c602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60006002805403610ce1576040517fad2ce74900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805560115473ffffffffffffffffffffffffffffffffffffffff16338114610d37576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff8116600174010000000000000000000000000000000000000000928390046affffffffffffffffffffff90811691820116909202179091559150610d9f82612b42565b610d3757610dad8183612c32565b50600160025590565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610e0d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff848116911614610ee8576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610f35576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff841614801590610f8c575073ffffffffffffffffffffffffffffffffffffffff83166000908152600d6020908152604080832033845290915290205460ff16155b8015610fbc57506000818152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15610ff3576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8084166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01905593861680835284832080546001019055858352600a825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600c90925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a46110cb838383612d61565b505050565b6000600654461461114c57611147600354600454604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060055490565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630036111c2576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166112377f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611284576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61128d81612d7d565b6112a881604051806020016040528060008152506000612f62565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611302576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b60004282106113ba576040517f118818d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600f6020526040812054908190036113f2576000915050610af2565b73ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85018085529281905292205467ffffffffffffffff168510611496576000908152602091909152604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169150610af29050565b60008080526020839052604090205467ffffffffffffffff168510156114c25760009350505050610af2565b60408051808201909152600080825260208201819052829181905b828411156115a05760028385030484036000818152602088815260409182902082518084019093525467ffffffffffffffff81168084526801000000000000000090910477ffffffffffffffffffffffffffffffffffffffffffffffff1691830191909152919350915089900361157a576020015177ffffffffffffffffffffffffffffffffffffffffffffffff169650610af295505050505050565b805167ffffffffffffffff16891115611595578192506114dd565b6001820393506114dd565b505060009081526020939093525050604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff1691505092915050565b6115ee838383610e88565b813b151580156116cf57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156110cb576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115473ffffffffffffffffffffffffffffffffffffffff163314611757576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a8816130b5565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630036117cf576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166118447f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611891576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61189a82612d7d565b6118a682826001612f62565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461191b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600e602052604081205490911680156119765780611978565b825b9392505050565b6112a8338261313a565b600054610100900460ff16158015806119a6575060005460ff1615155b80156119c25750303b1515806119c2575060005460ff16600114155b156119f9576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611a5757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611ac6576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ace6131f8565b611ad782613240565b611ae188886132f9565b600080611af087890189614779565b5050505091509150611b0282826136b8565b50506012805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560118054928616929091169190911790558015611bbc57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b6000818152600a602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610af2576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff8216611c71576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff166000908152600b602052604090205490565b60015473ffffffffffffffffffffffffffffffffffffffff163314611ceb576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60098054610b05906146c0565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600f6020526040812054808203611de5576000611e5f565b73ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501845290915290205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff165b77ffffffffffffffffffffffffffffffffffffffffffffffff169392505050565b60115473ffffffffffffffffffffffffffffffffffffffff163314611ed1576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601154604080517f61d027b30000000000000000000000000000000000000000000000000000000081529051611f6d9273ffffffffffffffffffffffffffffffffffffffff16916361d027b391600480830192602092919082900301816000875af1158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f68919061486e565b613712565b565b336000818152600d6020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b83421115612040576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061204a6110d0565b73ffffffffffffffffffffffffffffffffffffffff88811660008181526007602090815260409182902080546001810190915582517f9ba0adc65ac9b85f9640562bd298ef1e78f86fbfbc6433772a69f08b092c5b238184015280840194909452938b166060840152608083019390935260a08083018a90528151808403909101815260c0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000060e083015260e282019290925261010281019190915261012201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa1580156121a0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116158061221a57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15612251576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bbc888861313a565b6011546060907f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff8111156122a2576122a261420d565b60405190808252806020026020018201604052801561230b57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816122c05790505b50905060005b828110156123be576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106123ab576123ab61488b565b6020908102919091010152600101612311565b5092915050565b6123d0858585610e88565b833b1515801561249f57506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a02906124379033908a908990899089906004016148ba565b6020604051808303816000875af1158015612456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247a919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156124d6576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6012546040517fc87b56dd0000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063c87b56dd90602401600060405180830381865afa15801561254d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610af29190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146125ea576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff81111561262e5761262e61420d565b60405190808252806020026020018201604052801561269757816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161264c5790505b50905060005b8281101561274a576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106127375761273761488b565b602090810291909101015260010161269d565b50604080516064808252610ca0820190925260009160208201610c808036833701905050905060005b82518110156129005760008382815181106127905761279061488b565b6020908102919091018101516000848152601383526040812080547fffffffffffffff000000000000000000000000000000000000000000000000001690559181015190925060ff1690036127e557506128f8565b6000816020015160ff166064816127fe576127fe61470d565b0460ff1690506000805b836020015160ff168110156128f3575b85828151811061282a5761282a61488b565b60209081029190910101511561284b57600190910190606482069150612818565b600082815260146020526040902080547fffffffffffffff0000000000000000000000000000000000000000000000000016905585516001908790849081106128965761289661488b565b6020026020010190151590811515815250507f6309c4a2f8a0b726702416b909c21dce80f888bf255698775cd12336acd16b958286866040516128db939291906149a7565b60405180910390a16064828401069150600101612808565b505050505b600101612773565b50601180547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081169091556012805490911690556040517f6fb4c002bf55855ac8dd687342fe82b08a0a20ea80a7588566bfc6703bae213f9061296690879087906149fd565b60405180910390a16124d685856132f9565b6040805160608101825260008082526020820181905291810191909152601460006129a4606485614a6d565b815260208082019290925260409081016000208151606081018352905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1693820193909352750100000000000000000000000000000000000000000090920463ffffffff169082015292915050565b601254604080517fe8a3d485000000000000000000000000000000000000000000000000000000008152905160609273ffffffffffffffffffffffffffffffffffffffff169163e8a3d4859160048083019260009291908290030181865afa158015612a96573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111479190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612b33576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a881613712565b3b151590565b600080612b50606484614a6d565b60008181526014602052604090205490915073ffffffffffffffffffffffffffffffffffffffff16612b855750600092915050565b6000818152601460205260409020547501000000000000000000000000000000000000000000900463ffffffff16421015612bf257600081815260146020526040902054612be99073ffffffffffffffffffffffffffffffffffffffff1684612c32565b50600192915050565b600090815260146020526040812080547fffffffffffffff0000000000000000000000000000000000000000000000000016905592915050565b50919050565b612c3c82826137de565b601180547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff811674010000000000000000000000000000000000000000918290046affffffffffffffffffffff908116600101169091021790556012546040517f25b4e7be0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906325b4e7be906024016020604051808303816000875af1158015612d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2b9190614aa8565b6118a6576040517f110e7d7800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110cb612d6d84611940565b612d7684611940565b600161391f565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612e00576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd612e7a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0f9190614aa8565b6112a8576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612f95576110cb83613b36565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561301a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261301791810190614ac5565b60015b613050576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146130a9576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506110cb838383613bec565b6130be81613c17565b50601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6affffffffffffffffffffff7401000000000000000000000000000000000000000080840482169290920116027fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff909116179055565b73ffffffffffffffffffffffffffffffffffffffff81166131585750805b600061316383611940565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600e602052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46110cb81836131f386611c22565b61391f565b600054610100900460ff16613239576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600255565b600054610100900460ff16613281576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b600080805b8381101561364f57600085858381811061331a5761331a61488b565b905060600201602001359050806000036133345750613647565b928301926063841115613373576040517f91cc635e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff8316600081815260136020526040902060019094019387878581811061339d5761339d61488b565b6133b392602060609092020190810191506141b0565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff919091161781558787858181106134055761340561488b565b83547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000606092909202939093016040013563ffffffff16027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16919091177401000000000000000000000000000000000000000060ff861602178255506000836064816134ac576134ac61470d565b0490506000805b85811015613640576134c482613d39565b60008181526014602052604090819020865481547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff9092169182178355885460ff740100000000000000000000000000000000000000009182900416027fffffffffffffffffffffff00000000000000000000000000000000000000000090911690911717808255875463ffffffff75010000000000000000000000000000000000000000009182900416027fffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffff909116179055519092507fe9af43aba12c8c691c53cf87a0d60c9ff279731244b2186b92c6a90b535a2d2c906136289084908890889092835260208301919091525473ffffffffffffffffffffffffffffffffffffffff8116604083015260a081811c60ff16606084015260a89190911c63ffffffff1660808301520190565b60405180910390a160648284010691506001016134b3565b5050505050505b6001016132fe565b506012805460ff9384167f01000000000000000000000000000000000000000000000000000000000000009081027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92831617909255601180549390941690910291161790555050565b600054610100900460ff166136f9576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60086137058382614b2c565b5060096110cb8282614b2c565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9092169190911790915560015416156112a857600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b73ffffffffffffffffffffffffffffffffffffffff821661382b576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613887576040517fdfa4c0d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000818152600b6020908152604080832080546001019055848352600a90915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46118a660008383612d61565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561395b5750600081115b156110cb5773ffffffffffffffffffffffffffffffffffffffff831615613a495773ffffffffffffffffffffffffffffffffffffffff83166000908152600f60205260408120549080808315613a345750505073ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613a4487858584868a8803613d7b565b505050505b73ffffffffffffffffffffffffffffffffffffffff8216156110cb5773ffffffffffffffffffffffffffffffffffffffff82166000908152600f60205260408120549080808315613b1d5750505073ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613b2d86858584868a8801613d7b565b50505050505050565b803b613b86576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401612f59565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b613bf583613ee8565b600082511180613c025750805b156110cb57613c118383613f3d565b50505050565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613c73576040517f29074bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055858352600a825280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600c9092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a46118a681600084612d61565b60005b60008281526014602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613d7757600190910190606482069150613d3c565b5090565b600085118015613d8a57504283145b15613df95773ffffffffffffffffffffffffffffffffffffffff861660009081526010602090815260408083208784529091529020805467ffffffffffffffff166801000000000000000077ffffffffffffffffffffffffffffffffffffffffffffffff841602179055613e8f565b73ffffffffffffffffffffffffffffffffffffffff8616600081815260106020908152604080832089845282528083204267ffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff871668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016179055928252600f905220805460010190555b604080518381526020810183905273ffffffffffffffffffffffffffffffffffffffff8816917fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724910160405180910390a2505050505050565b613ef181613b36565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b613f77576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1684604051613f9f9190614c46565b600060405180830381855af49150503d8060008114613fda576040519150601f19603f3d011682016040523d82523d6000602084013e613fdf565b606091505b5091509150613fee8282613ff7565b95945050505050565b60608215614006575080610af2565b8151156140165781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff00000000000000000000000000000000000000000000000000000000811681146112a857600080fd5b60006020828403121561408857600080fd5b813561197881614048565b60005b838110156140ae578181015183820152602001614096565b50506000910152565b60208152600082518060208401526140d6816040850160208701614093565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561411a57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146112a857600080fd5b6000806040838503121561415657600080fd5b823561416181614121565b946020939093013593505050565b60008060006060848603121561418457600080fd5b833561418f81614121565b9250602084013561419f81614121565b929592945050506040919091013590565b6000602082840312156141c257600080fd5b813561197881614121565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015160ff169082015260408083015163ffffffff169082015260608101610af2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156142835761428361420d565b604052919050565b600067ffffffffffffffff8211156142a5576142a561420d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006142e46142df8461428b565b61423c565b90508281528383830111156142f857600080fd5b828260208301376000602084830101529392505050565b6000806040838503121561432257600080fd5b823561432d81614121565b9150602083013567ffffffffffffffff81111561434957600080fd5b8301601f8101851361435a57600080fd5b614369858235602084016142d1565b9150509250929050565b60008083601f84011261438557600080fd5b50813567ffffffffffffffff81111561439d57600080fd5b6020830191508360206060830285010111156143b857600080fd5b9250929050565b60008083601f8401126143d157600080fd5b50813567ffffffffffffffff8111156143e957600080fd5b6020830191508360208285010111156143b857600080fd5b600080600080600080600060a0888a03121561441c57600080fd5b873567ffffffffffffffff8082111561443457600080fd5b6144408b838c01614373565b909950975060208a013591508082111561445957600080fd5b506144668a828b016143bf565b909650945050604088013561447a81614121565b9250606088013561448a81614121565b9150608088013561449a81614121565b8091505092959891949750929550565b80151581146112a857600080fd5b600080604083850312156144cb57600080fd5b82356144d681614121565b915060208301356144e6816144aa565b809150509250929050565b60008060008060008060c0878903121561450a57600080fd5b863561451581614121565b9550602087013561452581614121565b945060408701359350606087013560ff8116811461454257600080fd5b9598949750929560808101359460a0909101359350915050565b6020808252825182820181905260009190848201906040850190845b818110156145d1576145be838551805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b9284019260609290920191600101614578565b50909695505050505050565b6000806000806000608086880312156145f557600080fd5b853561460081614121565b9450602086013561461081614121565b935060408601359250606086013567ffffffffffffffff81111561463357600080fd5b61463f888289016143bf565b969995985093965092949392505050565b6000806020838503121561466357600080fd5b823567ffffffffffffffff81111561467a57600080fd5b61468685828601614373565b90969095509350505050565b600080604083850312156146a557600080fd5b82356146b081614121565b915060208301356144e681614121565b600181811c908216806146d457607f821691505b602082108103612c2c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006020828403121561474e57600080fd5b815161197881614048565b600082601f83011261476a57600080fd5b611978838335602085016142d1565b60008060008060008060c0878903121561479257600080fd5b863567ffffffffffffffff808211156147aa57600080fd5b6147b68a838b01614759565b975060208901359150808211156147cc57600080fd5b6147d88a838b01614759565b965060408901359150808211156147ee57600080fd5b6147fa8a838b01614759565b9550606089013591508082111561481057600080fd5b61481c8a838b01614759565b9450608089013591508082111561483257600080fd5b61483e8a838b01614759565b935060a089013591508082111561485457600080fd5b5061486189828a01614759565b9150509295509295509295565b60006020828403121561488057600080fd5b815161197881614121565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509695505050505050565b60006020828403121561494b57600080fd5b815167ffffffffffffffff81111561496257600080fd5b8201601f8101841361497357600080fd5b80516149816142df8261428b565b81815285602083850101111561499657600080fd5b613fee826020830160208601614093565b8381526020810183905260a081016149f56040830184805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b949350505050565b6020808252818101839052600090604080840186845b87811015614a60578135614a2681614121565b73ffffffffffffffffffffffffffffffffffffffff1683528185013585840152838201358484015260609283019290910190600101614a13565b5090979650505050505050565b600082614aa3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600060208284031215614aba57600080fd5b8151611978816144aa565b600060208284031215614ad757600080fd5b5051919050565b601f8211156110cb57600081815260208120601f850160051c81016020861015614b055750805b601f850160051c820191505b81811015614b2457828155600101614b11565b505050505050565b815167ffffffffffffffff811115614b4657614b4661420d565b614b5a81614b5484546146c0565b84614ade565b602080601f831160018114614bad5760008415614b775750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614b24565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614bfa57888601518255948401946001909101908401614bdb565b5085821015614c3657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60008251614c58818460208701614093565b919091019291505056fea26469706673582212200bfb0be60a592c669e79d483768719bea2aa6f04d756a989444646671fbb8a8564736f6c63430008100033000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174

Deployed Bytecode

0x6080604052600436106102e75760003560e01c806370a0823111610184578063b20d7fa9116100d6578063d9d3e0901161008a578063e8a3d48511610064578063e8a3d48514610988578063e985e9c51461099d578063f2fde38b146109f357600080fd5b8063d9d3e09014610902578063dc276e571461093d578063e30c39781461095d57600080fd5b8063b88d4fde116100bb578063b88d4fde146108a2578063c87b56dd146108c2578063d1bfda66146108e257600080fd5b8063b20d7fa914610860578063b73cdd191461088057600080fd5b80638da5cb5b116101385780639d8aefc2116101125780639d8aefc2146107e5578063a0a8e460146107fa578063a22cb4651461084057600080fd5b80638da5cb5b1461077f57806395d89b41146107b05780639ab24eb0146107c557600080fd5b806374fd46551161016957806374fd46551461070457806379ba50971461073f5780637d9f6db51461075457600080fd5b806370a08231146106a157806370ae92d2146106c157600080fd5b80633a46b1a81161023d57806352d1902d116101f15780636097bf62116101cb5780636097bf62146106365780636352211e14610656578063703199701461067657600080fd5b806352d1902d146105e1578063587cde1e146105f65780635c19a95c1461061657600080fd5b806342842e0e1161022257806342842e0e1461058e57806342966c68146105ae5780634f1ef286146105ce57600080fd5b80633a46b1a8146104b45780633bcb43f3146104d457600080fd5b806318160ddd1161029f5780633644e515116102795780633644e5151461045f5780633659cfe614610474578063395db2cd1461049457600080fd5b806318160ddd146103f057806323452b9c1461042a57806323b872dd1461043f57600080fd5b8063081812fc116102d0578063081812fc14610343578063095ea7b3146103ab5780631249c58b146103cd57600080fd5b806301ffc9a7146102ec57806306fdde0314610321575b600080fd5b3480156102f857600080fd5b5061030c610307366004614076565b610a13565b60405190151581526020015b60405180910390f35b34801561032d57600080fd5b50610336610af8565b60405161031891906140b7565b34801561034f57600080fd5b5061038661035e366004614108565b6000908152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610318565b3480156103b757600080fd5b506103cb6103c6366004614143565b610b86565b005b3480156103d957600080fd5b506103e2610ca4565b604051908152602001610318565b3480156103fc57600080fd5b506011547401000000000000000000000000000000000000000090046affffffffffffffffffffff166103e2565b34801561043657600080fd5b506103cb610db6565b34801561044b57600080fd5b506103cb61045a36600461416f565b610e88565b34801561046b57600080fd5b506103e26110d0565b34801561048057600080fd5b506103cb61048f3660046141b0565b611153565b3480156104a057600080fd5b506103cb6104af3660046141b0565b6112ab565b3480156104c057600080fd5b506103e26104cf366004614143565b61137f565b3480156104e057600080fd5b506105816104ef366004614108565b6040805160608082018352600080835260208084018290529284018190529384526013825292829020825193840183525473ffffffffffffffffffffffffffffffffffffffff8116845274010000000000000000000000000000000000000000810460ff16918401919091527501000000000000000000000000000000000000000000900463ffffffff169082015290565b60405161031891906141cd565b34801561059a57600080fd5b506103cb6105a936600461416f565b6115e3565b3480156105ba57600080fd5b506103cb6105c9366004614108565b611706565b6103cb6105dc36600461430f565b611760565b3480156105ed57600080fd5b506103e26118aa565b34801561060257600080fd5b506103866106113660046141b0565b611940565b34801561062257600080fd5b506103cb6106313660046141b0565b61197f565b34801561064257600080fd5b506103cb610651366004614401565b611989565b34801561066257600080fd5b50610386610671366004614108565b611bc6565b34801561068257600080fd5b5060125473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156106ad57600080fd5b506103e26106bc3660046141b0565b611c22565b3480156106cd57600080fd5b506103e26106dc3660046141b0565b73ffffffffffffffffffffffffffffffffffffffff1660009081526007602052604090205490565b34801561071057600080fd5b506011547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561074b57600080fd5b506103cb611c9a565b34801561076057600080fd5b5060115473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561078b57600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156107bc57600080fd5b50610336611da4565b3480156107d157600080fd5b506103e26107e03660046141b0565b611db1565b3480156107f157600080fd5b506103cb611e80565b34801561080657600080fd5b5060408051808201909152600581527f312e312e300000000000000000000000000000000000000000000000000000006020820152610336565b34801561084c57600080fd5b506103cb61085b3660046144b8565b611f6f565b34801561086c57600080fd5b506103cb61087b3660046144f1565b612006565b34801561088c57600080fd5b5061089561225b565b604051610318919061455c565b3480156108ae57600080fd5b506103cb6108bd3660046145dd565b6123c5565b3480156108ce57600080fd5b506103366108dd366004614108565b6124dd565b3480156108ee57600080fd5b506103cb6108fd366004614650565b612593565b34801561090e57600080fd5b506012547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561094957600080fd5b50610581610958366004614108565b612978565b34801561096957600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561099457600080fd5b50610336612a26565b3480156109a957600080fd5b5061030c6109b8366004614692565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600d6020908152604080832093909416825291909152205460ff1690565b3480156109ff57600080fd5b506103cb610a0e3660046141b0565b612adc565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610aa657507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610af257507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60088054610b05906146c0565b80601f0160208091040260200160405190810160405280929190818152602001828054610b31906146c0565b8015610b7e5780601f10610b5357610100808354040283529160200191610b7e565b820191906000526020600020905b815481529060010190602001808311610b6157829003601f168201915b505050505081565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114801590610bec575073ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020908152604080832033845290915290205460ff16155b15610c23576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600c602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60006002805403610ce1576040517fad2ce74900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805560115473ffffffffffffffffffffffffffffffffffffffff16338114610d37576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff8116600174010000000000000000000000000000000000000000928390046affffffffffffffffffffff90811691820116909202179091559150610d9f82612b42565b610d3757610dad8183612c32565b50600160025590565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610e0d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff848116911614610ee8576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610f35576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff841614801590610f8c575073ffffffffffffffffffffffffffffffffffffffff83166000908152600d6020908152604080832033845290915290205460ff16155b8015610fbc57506000818152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15610ff3576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8084166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01905593861680835284832080546001019055858352600a825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600c90925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a46110cb838383612d61565b505050565b6000600654461461114c57611147600354600454604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060055490565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d59891630036111c2576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d598973ffffffffffffffffffffffffffffffffffffffff166112377f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611284576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61128d81612d7d565b6112a881604051806020016040528060008152506000612f62565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611302576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b60004282106113ba576040517f118818d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600f6020526040812054908190036113f2576000915050610af2565b73ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85018085529281905292205467ffffffffffffffff168510611496576000908152602091909152604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169150610af29050565b60008080526020839052604090205467ffffffffffffffff168510156114c25760009350505050610af2565b60408051808201909152600080825260208201819052829181905b828411156115a05760028385030484036000818152602088815260409182902082518084019093525467ffffffffffffffff81168084526801000000000000000090910477ffffffffffffffffffffffffffffffffffffffffffffffff1691830191909152919350915089900361157a576020015177ffffffffffffffffffffffffffffffffffffffffffffffff169650610af295505050505050565b805167ffffffffffffffff16891115611595578192506114dd565b6001820393506114dd565b505060009081526020939093525050604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff1691505092915050565b6115ee838383610e88565b813b151580156116cf57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156110cb576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115473ffffffffffffffffffffffffffffffffffffffff163314611757576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a8816130b5565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d59891630036117cf576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d598973ffffffffffffffffffffffffffffffffffffffff166118447f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611891576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61189a82612d7d565b6118a682826001612f62565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d5989161461191b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600e602052604081205490911680156119765780611978565b825b9392505050565b6112a8338261313a565b600054610100900460ff16158015806119a6575060005460ff1615155b80156119c25750303b1515806119c2575060005460ff16600114155b156119f9576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611a5757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da71741614611ac6576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ace6131f8565b611ad782613240565b611ae188886132f9565b600080611af087890189614779565b5050505091509150611b0282826136b8565b50506012805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560118054928616929091169190911790558015611bbc57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b6000818152600a602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610af2576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff8216611c71576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff166000908152600b602052604090205490565b60015473ffffffffffffffffffffffffffffffffffffffff163314611ceb576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60098054610b05906146c0565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600f6020526040812054808203611de5576000611e5f565b73ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501845290915290205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff165b77ffffffffffffffffffffffffffffffffffffffffffffffff169392505050565b60115473ffffffffffffffffffffffffffffffffffffffff163314611ed1576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601154604080517f61d027b30000000000000000000000000000000000000000000000000000000081529051611f6d9273ffffffffffffffffffffffffffffffffffffffff16916361d027b391600480830192602092919082900301816000875af1158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f68919061486e565b613712565b565b336000818152600d6020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b83421115612040576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061204a6110d0565b73ffffffffffffffffffffffffffffffffffffffff88811660008181526007602090815260409182902080546001810190915582517f9ba0adc65ac9b85f9640562bd298ef1e78f86fbfbc6433772a69f08b092c5b238184015280840194909452938b166060840152608083019390935260a08083018a90528151808403909101815260c0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000060e083015260e282019290925261010281019190915261012201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa1580156121a0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116158061221a57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15612251576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bbc888861313a565b6011546060907f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff8111156122a2576122a261420d565b60405190808252806020026020018201604052801561230b57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816122c05790505b50905060005b828110156123be576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106123ab576123ab61488b565b6020908102919091010152600101612311565b5092915050565b6123d0858585610e88565b833b1515801561249f57506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a02906124379033908a908990899089906004016148ba565b6020604051808303816000875af1158015612456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247a919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156124d6576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6012546040517fc87b56dd0000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063c87b56dd90602401600060405180830381865afa15801561254d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610af29190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146125ea576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff81111561262e5761262e61420d565b60405190808252806020026020018201604052801561269757816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161264c5790505b50905060005b8281101561274a576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106127375761273761488b565b602090810291909101015260010161269d565b50604080516064808252610ca0820190925260009160208201610c808036833701905050905060005b82518110156129005760008382815181106127905761279061488b565b6020908102919091018101516000848152601383526040812080547fffffffffffffff000000000000000000000000000000000000000000000000001690559181015190925060ff1690036127e557506128f8565b6000816020015160ff166064816127fe576127fe61470d565b0460ff1690506000805b836020015160ff168110156128f3575b85828151811061282a5761282a61488b565b60209081029190910101511561284b57600190910190606482069150612818565b600082815260146020526040902080547fffffffffffffff0000000000000000000000000000000000000000000000000016905585516001908790849081106128965761289661488b565b6020026020010190151590811515815250507f6309c4a2f8a0b726702416b909c21dce80f888bf255698775cd12336acd16b958286866040516128db939291906149a7565b60405180910390a16064828401069150600101612808565b505050505b600101612773565b50601180547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081169091556012805490911690556040517f6fb4c002bf55855ac8dd687342fe82b08a0a20ea80a7588566bfc6703bae213f9061296690879087906149fd565b60405180910390a16124d685856132f9565b6040805160608101825260008082526020820181905291810191909152601460006129a4606485614a6d565b815260208082019290925260409081016000208151606081018352905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1693820193909352750100000000000000000000000000000000000000000090920463ffffffff169082015292915050565b601254604080517fe8a3d485000000000000000000000000000000000000000000000000000000008152905160609273ffffffffffffffffffffffffffffffffffffffff169163e8a3d4859160048083019260009291908290030181865afa158015612a96573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111479190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612b33576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a881613712565b3b151590565b600080612b50606484614a6d565b60008181526014602052604090205490915073ffffffffffffffffffffffffffffffffffffffff16612b855750600092915050565b6000818152601460205260409020547501000000000000000000000000000000000000000000900463ffffffff16421015612bf257600081815260146020526040902054612be99073ffffffffffffffffffffffffffffffffffffffff1684612c32565b50600192915050565b600090815260146020526040812080547fffffffffffffff0000000000000000000000000000000000000000000000000016905592915050565b50919050565b612c3c82826137de565b601180547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff811674010000000000000000000000000000000000000000918290046affffffffffffffffffffff908116600101169091021790556012546040517f25b4e7be0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906325b4e7be906024016020604051808303816000875af1158015612d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2b9190614aa8565b6118a6576040517f110e7d7800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110cb612d6d84611940565b612d7684611940565b600161391f565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612e00576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da717473ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd612e7a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0f9190614aa8565b6112a8576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612f95576110cb83613b36565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561301a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261301791810190614ac5565b60015b613050576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146130a9576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506110cb838383613bec565b6130be81613c17565b50601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6affffffffffffffffffffff7401000000000000000000000000000000000000000080840482169290920116027fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff909116179055565b73ffffffffffffffffffffffffffffffffffffffff81166131585750805b600061316383611940565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600e602052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46110cb81836131f386611c22565b61391f565b600054610100900460ff16613239576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600255565b600054610100900460ff16613281576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b600080805b8381101561364f57600085858381811061331a5761331a61488b565b905060600201602001359050806000036133345750613647565b928301926063841115613373576040517f91cc635e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff8316600081815260136020526040902060019094019387878581811061339d5761339d61488b565b6133b392602060609092020190810191506141b0565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff919091161781558787858181106134055761340561488b565b83547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000606092909202939093016040013563ffffffff16027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16919091177401000000000000000000000000000000000000000060ff861602178255506000836064816134ac576134ac61470d565b0490506000805b85811015613640576134c482613d39565b60008181526014602052604090819020865481547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff9092169182178355885460ff740100000000000000000000000000000000000000009182900416027fffffffffffffffffffffff00000000000000000000000000000000000000000090911690911717808255875463ffffffff75010000000000000000000000000000000000000000009182900416027fffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffff909116179055519092507fe9af43aba12c8c691c53cf87a0d60c9ff279731244b2186b92c6a90b535a2d2c906136289084908890889092835260208301919091525473ffffffffffffffffffffffffffffffffffffffff8116604083015260a081811c60ff16606084015260a89190911c63ffffffff1660808301520190565b60405180910390a160648284010691506001016134b3565b5050505050505b6001016132fe565b506012805460ff9384167f01000000000000000000000000000000000000000000000000000000000000009081027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92831617909255601180549390941690910291161790555050565b600054610100900460ff166136f9576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60086137058382614b2c565b5060096110cb8282614b2c565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9092169190911790915560015416156112a857600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b73ffffffffffffffffffffffffffffffffffffffff821661382b576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613887576040517fdfa4c0d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000818152600b6020908152604080832080546001019055848352600a90915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46118a660008383612d61565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561395b5750600081115b156110cb5773ffffffffffffffffffffffffffffffffffffffff831615613a495773ffffffffffffffffffffffffffffffffffffffff83166000908152600f60205260408120549080808315613a345750505073ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613a4487858584868a8803613d7b565b505050505b73ffffffffffffffffffffffffffffffffffffffff8216156110cb5773ffffffffffffffffffffffffffffffffffffffff82166000908152600f60205260408120549080808315613b1d5750505073ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613b2d86858584868a8801613d7b565b50505050505050565b803b613b86576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401612f59565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b613bf583613ee8565b600082511180613c025750805b156110cb57613c118383613f3d565b50505050565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613c73576040517f29074bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055858352600a825280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600c9092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a46118a681600084612d61565b60005b60008281526014602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613d7757600190910190606482069150613d3c565b5090565b600085118015613d8a57504283145b15613df95773ffffffffffffffffffffffffffffffffffffffff861660009081526010602090815260408083208784529091529020805467ffffffffffffffff166801000000000000000077ffffffffffffffffffffffffffffffffffffffffffffffff841602179055613e8f565b73ffffffffffffffffffffffffffffffffffffffff8616600081815260106020908152604080832089845282528083204267ffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff871668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016179055928252600f905220805460010190555b604080518381526020810183905273ffffffffffffffffffffffffffffffffffffffff8816917fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724910160405180910390a2505050505050565b613ef181613b36565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b613f77576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1684604051613f9f9190614c46565b600060405180830381855af49150503d8060008114613fda576040519150601f19603f3d011682016040523d82523d6000602084013e613fdf565b606091505b5091509150613fee8282613ff7565b95945050505050565b60608215614006575080610af2565b8151156140165781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff00000000000000000000000000000000000000000000000000000000811681146112a857600080fd5b60006020828403121561408857600080fd5b813561197881614048565b60005b838110156140ae578181015183820152602001614096565b50506000910152565b60208152600082518060208401526140d6816040850160208701614093565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561411a57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146112a857600080fd5b6000806040838503121561415657600080fd5b823561416181614121565b946020939093013593505050565b60008060006060848603121561418457600080fd5b833561418f81614121565b9250602084013561419f81614121565b929592945050506040919091013590565b6000602082840312156141c257600080fd5b813561197881614121565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015160ff169082015260408083015163ffffffff169082015260608101610af2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156142835761428361420d565b604052919050565b600067ffffffffffffffff8211156142a5576142a561420d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006142e46142df8461428b565b61423c565b90508281528383830111156142f857600080fd5b828260208301376000602084830101529392505050565b6000806040838503121561432257600080fd5b823561432d81614121565b9150602083013567ffffffffffffffff81111561434957600080fd5b8301601f8101851361435a57600080fd5b614369858235602084016142d1565b9150509250929050565b60008083601f84011261438557600080fd5b50813567ffffffffffffffff81111561439d57600080fd5b6020830191508360206060830285010111156143b857600080fd5b9250929050565b60008083601f8401126143d157600080fd5b50813567ffffffffffffffff8111156143e957600080fd5b6020830191508360208285010111156143b857600080fd5b600080600080600080600060a0888a03121561441c57600080fd5b873567ffffffffffffffff8082111561443457600080fd5b6144408b838c01614373565b909950975060208a013591508082111561445957600080fd5b506144668a828b016143bf565b909650945050604088013561447a81614121565b9250606088013561448a81614121565b9150608088013561449a81614121565b8091505092959891949750929550565b80151581146112a857600080fd5b600080604083850312156144cb57600080fd5b82356144d681614121565b915060208301356144e6816144aa565b809150509250929050565b60008060008060008060c0878903121561450a57600080fd5b863561451581614121565b9550602087013561452581614121565b945060408701359350606087013560ff8116811461454257600080fd5b9598949750929560808101359460a0909101359350915050565b6020808252825182820181905260009190848201906040850190845b818110156145d1576145be838551805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b9284019260609290920191600101614578565b50909695505050505050565b6000806000806000608086880312156145f557600080fd5b853561460081614121565b9450602086013561461081614121565b935060408601359250606086013567ffffffffffffffff81111561463357600080fd5b61463f888289016143bf565b969995985093965092949392505050565b6000806020838503121561466357600080fd5b823567ffffffffffffffff81111561467a57600080fd5b61468685828601614373565b90969095509350505050565b600080604083850312156146a557600080fd5b82356146b081614121565b915060208301356144e681614121565b600181811c908216806146d457607f821691505b602082108103612c2c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006020828403121561474e57600080fd5b815161197881614048565b600082601f83011261476a57600080fd5b611978838335602085016142d1565b60008060008060008060c0878903121561479257600080fd5b863567ffffffffffffffff808211156147aa57600080fd5b6147b68a838b01614759565b975060208901359150808211156147cc57600080fd5b6147d88a838b01614759565b965060408901359150808211156147ee57600080fd5b6147fa8a838b01614759565b9550606089013591508082111561481057600080fd5b61481c8a838b01614759565b9450608089013591508082111561483257600080fd5b61483e8a838b01614759565b935060a089013591508082111561485457600080fd5b5061486189828a01614759565b9150509295509295509295565b60006020828403121561488057600080fd5b815161197881614121565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509695505050505050565b60006020828403121561494b57600080fd5b815167ffffffffffffffff81111561496257600080fd5b8201601f8101841361497357600080fd5b80516149816142df8261428b565b81815285602083850101111561499657600080fd5b613fee826020830160208601614093565b8381526020810183905260a081016149f56040830184805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b949350505050565b6020808252818101839052600090604080840186845b87811015614a60578135614a2681614121565b73ffffffffffffffffffffffffffffffffffffffff1683528185013585840152838201358484015260609283019290910190600101614a13565b5090979650505050505050565b600082614aa3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600060208284031215614aba57600080fd5b8151611978816144aa565b600060208284031215614ad757600080fd5b5051919050565b601f8211156110cb57600081815260208120601f850160051c81016020861015614b055750805b601f850160051c820191505b81811015614b2457828155600101614b11565b505050505050565b815167ffffffffffffffff811115614b4657614b4661420d565b614b5a81614b5484546146c0565b84614ade565b602080601f831160018114614bad5760008415614b775750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614b24565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614bfa57888601518255948401946001909101908401614bdb565b5085821015614c3657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60008251614c58818460208701614093565b919091019291505056fea26469706673582212200bfb0be60a592c669e79d483768719bea2aa6f04d756a989444646671fbb8a8564736f6c63430008100033

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

000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174

-----Decoded View---------------
Arg [0] : _manager (address): 0xd310A3041dFcF14Def5ccBc508668974b5da7174

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174


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

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.