ETH Price: $2,268.58 (+7.60%)

Contract

0xaaF173E6b65aa4473C830EDB402D26B7A33c5E94
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

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
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Rewards

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 28 : Rewards.sol
// SPDX-License-Identifier: GPL-3.0

/// @title The client incentives rewards logic

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.19;

import { INounsDAOLogic } from '../interfaces/INounsDAOLogic.sol';
import { INounsAuctionHouseV2 } from '../interfaces/INounsAuctionHouseV2.sol';
import { NounsDAOTypes } from '../governance/NounsDAOInterfaces.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { UUPSUpgradeable } from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol';
import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol';
import { ClientRewardsMemoryMapping } from '../libs/ClientRewardsMemoryMapping.sol';
import { GasRefund } from '../libs/GasRefund.sol';
import { INounsClientTokenDescriptor } from './INounsClientTokenDescriptor.sol';
import { INounsClientTokenTypes } from './INounsClientTokenTypes.sol';
import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import { ERC721Upgradeable } from '@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol';
import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol';

contract Rewards is
    UUPSUpgradeable,
    PausableUpgradeable,
    OwnableUpgradeable,
    ERC721Upgradeable,
    INounsClientTokenTypes
{
    using SafeERC20 for IERC20;
    using ClientRewardsMemoryMapping for ClientRewardsMemoryMapping.Mapping;

    error RewardsDisabled();
    error OnlyOwnerOrAdmin();
    error OnlyNFTOwner();
    error LastNounIdMustBeSettled();
    error LastNounIdMustBeHigher();

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   EVENTS
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    event ClientRegistered(uint32 indexed clientId, string name, string description);
    event ClientUpdated(uint32 indexed clientId, string name, string description);
    event ClientRewarded(uint32 indexed clientId, uint256 amount);
    event ClientBalanceWithdrawal(uint32 indexed clientId, uint256 amount, address to);
    event AuctionRewardsUpdated(uint256 firstAuctionId, uint256 lastAuctionId);
    event ProposalRewardsUpdated(
        uint32 firstProposalId,
        uint32 lastProposalId,
        uint256 firstAuctionIdForRevenue,
        uint256 lastAuctionIdForRevenue,
        uint256 auctionRevenue,
        uint256 rewardPerProposal,
        uint256 rewardPerVote
    );
    event ClientApprovalSet(uint32 indexed clientId, bool approved);
    event AuctionRewardsEnabled(uint32 nextAuctionIdToReward);
    event AuctionRewardsDisabled();
    event ProposalRewardsEnabled(uint32 nextProposalIdToReward, uint32 nextProposalRewardFirstAuctionId);
    event ProposalRewardsDisabled();

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   IMMUTABLES
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    /// @notice Nouns DAO proxy contract
    INounsDAOLogic public immutable nounsDAO;

    /// @notice Nouns Auction House proxy contract
    INounsAuctionHouseV2 public immutable auctionHouse;

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   STORAGE VARIABLES
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    struct ProposalRewardParams {
        /// @dev The minimum reward period for proposal updates if number of proposals is below `numProposalsEnoughForReward`
        uint32 minimumRewardPeriod;
        /// @dev The number of proposals required for an update before `minimumRewardPeriod` has passed
        uint8 numProposalsEnoughForReward;
        /// @dev How much bips out of the auction revenue during this period to use for rewarding proposal creation
        uint16 proposalRewardBps;
        /// @dev How much bips out of the auction revenue during this period to use for rewarding proposal voting
        uint16 votingRewardBps;
        /// @dev How many (in bips) FOR votes out of total votes are required for a proposal to be eligible for rewards
        uint16 proposalEligibilityQuorumBps;
    }

    struct AuctionRewardParams {
        /// @dev How much bips out of auction revnue to use for rewarding auction bidding
        uint16 auctionRewardBps;
        /// @dev Minimum number of auctions between updates. Zero means 1 auction is enough.
        uint8 minimumAuctionsBetweenUpdates;
    }

    /// @custom:storage-location erc7201:nouns.rewards
    struct RewardsStorage {
        /// @dev The next client token id to be minted
        uint32 nextTokenId;
        /// @dev Flag controlling if auction rewards are enabled
        bool auctionRewardsEnabled;
        /// @dev Used for auction rewards state
        uint32 nextAuctionIdToReward;
        /// @dev Flag controlling if proposal rewards are enabled
        bool proposalRewardsEnabled;
        /// @dev Used for proposal rewards state
        uint32 nextProposalIdToReward;
        /// @dev The first auction id to consider for revenue tracking on the next proposal rewards update
        uint32 nextProposalRewardFirstAuctionId;
        /// @dev Last time the proposal rewards update was performed
        uint40 lastProposalRewardsUpdate;
        /// @dev Params for both proposal rewards
        ProposalRewardParams proposalRewardParams;
        /// @dev Params for auction rewards
        AuctionRewardParams auctionRewardParams;
        /// @dev An ETH pegged ERC20 token to use for rewarding
        IERC20 ethToken;
        /// @dev admin account able to pause/unpause the contract in case of a quick response is needed
        address admin;
        /// @dev client metadata per clientId, including rewards balances, name, description
        mapping(uint32 clientId => ClientMetadata) _clientMetadata;
        /// @dev The client NFT descriptor
        address descriptor;
    }

    /// @dev This is a ERC-7201 storage location, calculated using:
    /// @dev keccak256(abi.encode(uint256(keccak256("nouns.rewards")) - 1)) & ~bytes32(uint256(0xff));
    bytes32 public constant RewardsStorageLocation = 0x9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd700;

    function _getRewardsStorage() private pure returns (RewardsStorage storage $) {
        assembly {
            $.slot := RewardsStorageLocation
        }
    }

    /**
     * @dev Reverts if called by any account other than the owner or admin.
     */
    modifier onlyOwnerOrAdmin() {
        RewardsStorage storage $ = _getRewardsStorage();
        if (!(owner() == _msgSender() || $.admin == _msgSender())) revert OnlyOwnerOrAdmin();
        _;
    }

    constructor(address nounsDAO_, address auctionHouse_) initializer {
        nounsDAO = INounsDAOLogic(nounsDAO_);
        auctionHouse = INounsAuctionHouseV2(auctionHouse_);
    }

    /**
     * @param owner Address of the owner who has administration permissions as well as contract upgrade permissions
     * @param admin_ Address which has permissions to pause and unpause
     * @param ethToken_ An ETH pegged token (e.g. WETH) which will be used for rewards and gas refunds
     * @param descriptor_ Address of a INounsClientTokenDescriptor contract to provide tokenURI for the NFTs
     */
    function initialize(address owner, address admin_, address ethToken_, address descriptor_) public initializer {
        __Pausable_init_unchained();
        __ERC721_init('Nouns Client Token', 'NOUNSCLIENT');

        RewardsStorage storage $ = _getRewardsStorage();
        $.nextTokenId = 1;

        _transferOwnership(owner);
        $.admin = admin_;
        $.ethToken = IERC20(ethToken_);
        $.descriptor = descriptor_;
    }

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   PUBLIC WRITE
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    /**
     * @notice Register a client, mints an NFT and assigns a clientId
     * @param name a short name identifying the client
     * @param description a longer description for the client, ideally a URL
     * @return uint32 the newly assigned clientId
     */
    function registerClient(string calldata name, string calldata description) external whenNotPaused returns (uint32) {
        RewardsStorage storage $ = _getRewardsStorage();

        uint32 tokenId = $.nextTokenId;
        $.nextTokenId = tokenId + 1;
        _mint(msg.sender, tokenId);

        ClientMetadata storage md = $._clientMetadata[tokenId];
        md.name = name;
        md.description = description;

        emit ClientRegistered(tokenId, name, description);

        return tokenId;
    }

    /**
     * @notice Update the metadata of a client
     * @dev Only the owner of the client token can update the metadata.
     * @param tokenId The token ID of the client
     * @param name The new name of the client
     * @param description The new description of the client
     */
    function updateClientMetadata(uint32 tokenId, string calldata name, string calldata description) external {
        RewardsStorage storage $ = _getRewardsStorage();

        if (ownerOf(tokenId) != msg.sender) revert OnlyNFTOwner();
        ClientMetadata storage md = $._clientMetadata[tokenId];
        md.name = name;
        md.description = description;

        emit ClientUpdated(tokenId, name, description);
    }

    /**
     * @notice Distribute rewards for auction bidding since the last update until auction with id `lastNounId`
     * If an auction's winning bid was called with a clientId, that client will be reward with `params.auctionRewardBps`
     * bips of the auction's settlement amount.
     * At least `minimumAuctionsBetweenUpdates` must happen between updates.
     * Gas spent is refunded in `ethToken`.
     * @param lastNounId the last auction id to reward client for. must be already settled.
     * @dev Gas is refunded if at least one auction was rewarded
     */
    function updateRewardsForAuctions(uint32 lastNounId) public whenNotPaused {
        uint256 startGas = gasleft();
        RewardsStorage storage $ = _getRewardsStorage();
        if (!$.auctionRewardsEnabled) revert RewardsDisabled();

        bool sawValidClientId = false;
        uint256 nextAuctionIdToReward_ = $.nextAuctionIdToReward;
        if (lastNounId < nextAuctionIdToReward_ + $.auctionRewardParams.minimumAuctionsBetweenUpdates)
            revert LastNounIdMustBeHigher();

        $.nextAuctionIdToReward = lastNounId + 1;

        INounsAuctionHouseV2.Settlement[] memory settlements = auctionHouse.getSettlements(
            nextAuctionIdToReward_,
            lastNounId + 1,
            true
        );
        INounsAuctionHouseV2.Settlement memory lastSettlement = settlements[settlements.length - 1];
        if (!(lastSettlement.nounId == lastNounId && lastSettlement.blockTimestamp > 1))
            revert LastNounIdMustBeSettled();

        uint32 maxClientId = nextTokenId() - 1;
        ClientRewardsMemoryMapping.Mapping memory m = ClientRewardsMemoryMapping.createMapping({
            maxClientId: maxClientId
        });

        for (uint256 i; i < settlements.length; ++i) {
            INounsAuctionHouseV2.Settlement memory settlement = settlements[i];
            if (settlement.clientId != 0 && settlement.clientId <= maxClientId) {
                sawValidClientId = true;
                m.inc(settlement.clientId, settlement.amount);
            }
        }

        uint16 auctionRewardBps = $.auctionRewardParams.auctionRewardBps;
        uint256 numValues = m.numValues();
        for (uint32 i = 0; i < numValues; ++i) {
            ClientRewardsMemoryMapping.ClientBalance memory cb = m.getValue(i);
            uint256 reward = (cb.balance * auctionRewardBps) / 10_000;
            $._clientMetadata[cb.clientId].rewarded += SafeCast.toUint96(reward);

            emit ClientRewarded(cb.clientId, reward);
        }

        emit AuctionRewardsUpdated(nextAuctionIdToReward_, lastNounId);

        if (sawValidClientId) {
            // refund gas only if we're actually rewarding a client, not just moving the pointer
            GasRefund.refundGas($.ethToken, startGas);
        }
    }

    /// @dev struct used to avoid stack-too-deep errors
    struct Temp {
        uint32 maxClientId;
        uint256 numEligibleVotes;
        uint256 rewardPerProposal;
        uint256 rewardPerVote;
        uint256 proposalRewardForPeriod;
        uint256 votingRewardForPeriod;
        uint256 firstAuctionIdForRevenue;
        NounsDAOTypes.ProposalForRewards lastProposal;
    }

    /**
     * @notice Distribute rewards for proposal creation and voting from the last update until `lastProposalId`.
     * A proposal is eligible for rewards if it wasn't canceled and for-votes/total-votes >= params.proposalEligibilityQuorumBps.
     * Rewards are calculated by the auctions revenue during the period between the creation time of last processed
     * eligible proposal in until the current last eligible proposal with id <= `lastProposalId`.
     * One of two conditions must be true in order for rewards to be distributed:
     * 1. There are at least `numProposalsEnoughForReward` proposals in this update
     * 2. At least `minimumRewardPeriod` time has passed since the last update until the creation time of the last
     *     eligible proposal in this update.
     * Gas spent is refunded in `ethToken`.
     * @param lastProposalId id of the last proposal to include in the rewards distribution. all proposals up to and
     * including this id must have ended voting.
     * @param votingClientIds array of sorted client ids that were used to vote on the eligible proposals in
     * this rewards distribution. Reverts if it contains duplicates. Reverts if it's not sorted. Reverts if a clientId
     * had zero votes on all eligible proposals from this update.
     * You may use `getVotingClientIds` as a convenience function to get the correct `votingClientIds`.
     */
    function updateRewardsForProposalWritingAndVoting(
        uint32 lastProposalId,
        uint32[] calldata votingClientIds
    ) public whenNotPaused {
        uint256 startGas = gasleft();
        RewardsStorage storage $ = _getRewardsStorage();
        if (!$.proposalRewardsEnabled) revert RewardsDisabled();

        Temp memory t;

        t.maxClientId = nextTokenId() - 1;
        uint32 nextProposalIdToReward_ = $.nextProposalIdToReward;

        require(
            (lastProposalId <= nounsDAO.proposalCount()) && (lastProposalId >= nextProposalIdToReward_),
            'bad lastProposalId'
        );
        require(isSortedAndNoDuplicates(votingClientIds), 'must be sorted & unique');

        NounsDAOTypes.ProposalForRewards[] memory proposals = nounsDAO.proposalDataForRewards({
            firstProposalId: nextProposalIdToReward_,
            lastProposalId: lastProposalId,
            proposalEligibilityQuorumBps: $.proposalRewardParams.proposalEligibilityQuorumBps,
            excludeCanceled: true,
            requireVotingEnded: true,
            votingClientIds: votingClientIds
        });
        require(proposals.length > 0, 'at least one eligible proposal');
        $.nextProposalIdToReward = lastProposalId + 1;

        t.lastProposal = proposals[proposals.length - 1];

        t.firstAuctionIdForRevenue = $.nextProposalRewardFirstAuctionId;
        (uint256 auctionRevenue, uint256 lastAuctionIdForRevenue) = getAuctionRevenue({
            firstNounId: t.firstAuctionIdForRevenue,
            endTimestamp: t.lastProposal.creationTimestamp
        });
        $.nextProposalRewardFirstAuctionId = uint32(lastAuctionIdForRevenue) + 1;

        require(auctionRevenue > 0, 'auctionRevenue must be > 0');

        t.proposalRewardForPeriod = (auctionRevenue * $.proposalRewardParams.proposalRewardBps) / 10_000;
        t.votingRewardForPeriod = (auctionRevenue * $.proposalRewardParams.votingRewardBps) / 10_000;

        //// First loop over the proposals:
        //// 1. Count the number of votes in eligible proposals.

        for (uint256 i; i < proposals.length; ++i) {
            uint256 votesInProposal = proposals[i].forVotes + proposals[i].againstVotes + proposals[i].abstainVotes;
            t.numEligibleVotes += votesInProposal;
        }

        //// Check that distribution is allowed:
        //// 1. One of the two conditions must be true:
        //// 1.a. Number of eligible proposals is at least `numProposalsEnoughForReward`.
        //// 1.b. At least `minimumRewardPeriod` seconds have passed since the last update.

        if (proposals.length < $.proposalRewardParams.numProposalsEnoughForReward) {
            require(
                t.lastProposal.creationTimestamp >
                    $.lastProposalRewardsUpdate + $.proposalRewardParams.minimumRewardPeriod,
                'not enough time passed'
            );
        }
        $.lastProposalRewardsUpdate = uint40(t.lastProposal.creationTimestamp);

        // Calculate the reward per proposal and per vote
        t.rewardPerProposal = t.proposalRewardForPeriod / proposals.length;
        t.rewardPerVote = t.votingRewardForPeriod / t.numEligibleVotes;

        emit ProposalRewardsUpdated(
            nextProposalIdToReward_,
            lastProposalId,
            t.firstAuctionIdForRevenue,
            lastAuctionIdForRevenue,
            auctionRevenue,
            t.rewardPerProposal,
            t.rewardPerVote
        );

        //// Second loop over the proposals:
        //// 1. Reward proposal's clientId.
        //// 2. Reward the clientIds that faciliated voting.
        //// 3. Make sure all voting clientIds were included. This is meant to avoid griefing. Otherwises one could pass
        ////    a large array of votingClientIds, spend a lot of gas, and have that gas refunded.

        ClientRewardsMemoryMapping.Mapping memory m = ClientRewardsMemoryMapping.createMapping({
            maxClientId: t.maxClientId
        });
        bool[] memory didClientIdHaveVotes = new bool[](votingClientIds.length);

        for (uint256 i; i < proposals.length; ++i) {
            uint32 clientId = proposals[i].clientId;
            if (clientId != 0 && clientId <= t.maxClientId) {
                m.inc(clientId, t.rewardPerProposal);
            }

            uint256 votesInProposal;
            NounsDAOTypes.ClientVoteData[] memory voteData = proposals[i].voteData;
            for (uint256 j; j < votingClientIds.length; ++j) {
                clientId = votingClientIds[j];
                uint256 votes = voteData[j].votes;
                didClientIdHaveVotes[j] = didClientIdHaveVotes[j] || votes > 0;
                if (clientId != 0 && clientId <= t.maxClientId) {
                    m.inc(clientId, votes * t.rewardPerVote);
                }
                votesInProposal += votes;
            }
            require(
                votesInProposal == proposals[i].forVotes + proposals[i].againstVotes + proposals[i].abstainVotes,
                'not all votes accounted'
            );
        }

        for (uint256 i = 0; i < didClientIdHaveVotes.length; ++i) {
            require(didClientIdHaveVotes[i], 'all clientId must have votes');
        }

        uint256 numValues = m.numValues();
        for (uint32 i = 0; i < numValues; ++i) {
            ClientRewardsMemoryMapping.ClientBalance memory cb = m.getValue(i);
            $._clientMetadata[cb.clientId].rewarded += SafeCast.toUint96(cb.balance);
            emit ClientRewarded(cb.clientId, cb.balance);
        }

        GasRefund.refundGas($.ethToken, startGas);
    }

    /**
     * @notice Withdraws the balance of a client
     * @dev The caller must be the owner of the NFT with id `clientId` and the client must be approved by the DAO.
     * @param clientId Which client balance to withdraw
     * @param to the address to withdraw to
     * @param amount amount to withdraw
     */
    function withdrawClientBalance(uint32 clientId, address to, uint96 amount) public whenNotPaused {
        RewardsStorage storage $ = _getRewardsStorage();
        ClientMetadata storage md = $._clientMetadata[clientId];

        if (ownerOf(clientId) != msg.sender) revert OnlyNFTOwner();
        require(md.approved, 'not approved');

        uint96 withdrawnCache = md.withdrawn;
        require(amount <= md.rewarded - withdrawnCache, 'amount too large');

        md.withdrawn = withdrawnCache + amount;

        emit ClientBalanceWithdrawal(clientId, amount, to);

        $.ethToken.safeTransfer(to, amount);
    }

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   PUBLIC READ
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    /**
     * @notice Returns the withdrawable balance of client with id `clientId`
     */
    function clientBalance(uint32 clientId) public view returns (uint96) {
        RewardsStorage storage $ = _getRewardsStorage();
        ClientMetadata storage md = $._clientMetadata[clientId];
        return md.rewarded - md.withdrawn;
    }

    /**
     * @notice Returns the clientIds that are needed to be passed as a parameter to updateRewardsForProposalWritingAndVoting
     * @dev This is not meant to be called onchain because it may be very gas intensive.
     */
    function getVotingClientIds(uint32 lastProposalId) public view returns (uint32[] memory) {
        RewardsStorage storage $ = _getRewardsStorage();

        uint256 numClientIds = nextTokenId();
        uint32[] memory allClientIds = new uint32[](numClientIds);
        for (uint32 i; i < numClientIds; ++i) {
            allClientIds[i] = i;
        }
        NounsDAOTypes.ProposalForRewards[] memory proposals = nounsDAO.proposalDataForRewards({
            firstProposalId: $.nextProposalIdToReward,
            lastProposalId: lastProposalId,
            proposalEligibilityQuorumBps: $.proposalRewardParams.proposalEligibilityQuorumBps,
            excludeCanceled: true,
            requireVotingEnded: true,
            votingClientIds: allClientIds
        });

        uint32[] memory sumVotes = new uint32[](numClientIds);
        for (uint256 i; i < proposals.length; ++i) {
            for (uint256 j; j < numClientIds; ++j) {
                sumVotes[j] += proposals[i].voteData[j].votes;
            }
        }

        uint256 idx;
        uint32[] memory nonZeroClientIds = new uint32[](numClientIds);
        for (uint32 i; i < numClientIds; ++i) {
            if (sumVotes[i] > 0) nonZeroClientIds[idx++] = i;
        }

        assembly {
            mstore(nonZeroClientIds, idx)
        }

        return nonZeroClientIds;
    }

    /**
     * @notice Returns the sum of revenue via auctions from auctioning noun with id `firstNounId` until timestamp of `endTimestamp
     */
    function getAuctionRevenue(
        uint256 firstNounId,
        uint256 endTimestamp
    ) public view returns (uint256 sumRevenue, uint256 lastAuctionId) {
        INounsAuctionHouseV2.Settlement[] memory s = auctionHouse.getSettlementsFromIdtoTimestamp(
            firstNounId,
            endTimestamp,
            true
        );
        sumRevenue = sumAuctions(s);
        lastAuctionId = s[s.length - 1].nounId;
    }

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   PUBLIC READ - STORAGE GETTERS
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    function nextAuctionIdToReward() public view returns (uint256) {
        return _getRewardsStorage().nextAuctionIdToReward;
    }

    function nextProposalIdToReward() public view returns (uint32) {
        return _getRewardsStorage().nextProposalIdToReward;
    }

    function nextProposalRewardFirstAuctionId() public view returns (uint256) {
        return _getRewardsStorage().nextProposalRewardFirstAuctionId;
    }

    function lastProposalRewardsUpdate() public view returns (uint256) {
        return _getRewardsStorage().lastProposalRewardsUpdate;
    }

    function getAuctionRewardParams() public view returns (AuctionRewardParams memory) {
        return _getRewardsStorage().auctionRewardParams;
    }

    function getProposalRewardParams() public view returns (ProposalRewardParams memory) {
        return _getRewardsStorage().proposalRewardParams;
    }

    function auctionRewardsEnabled() public view returns (bool) {
        return _getRewardsStorage().auctionRewardsEnabled;
    }

    function proposalRewardsEnabled() public view returns (bool) {
        return _getRewardsStorage().proposalRewardsEnabled;
    }

    function ethToken() public view returns (IERC20) {
        return _getRewardsStorage().ethToken;
    }

    function admin() public view returns (address) {
        return _getRewardsStorage().admin;
    }

    /**
     * @notice Get the metadata of a client
     */
    function clientMetadata(uint32 tokenId) public view returns (ClientMetadata memory) {
        return _getRewardsStorage()._clientMetadata[tokenId];
    }

    /**
     * @notice Get the URI of a client token
     */
    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        RewardsStorage storage $ = _getRewardsStorage();
        return INounsClientTokenDescriptor($.descriptor).tokenURI(tokenId, $._clientMetadata[uint32(tokenId)]);
    }

    /**
     * @notice Get the descriptor for the client token
     */
    function descriptor() public view returns (address) {
        return _getRewardsStorage().descriptor;
    }

    /**
     * @notice Get the next token ID
     */
    function nextTokenId() public view returns (uint32) {
        return _getRewardsStorage().nextTokenId;
    }

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   ADMIN
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    /**
     * @notice Set whether the client is approved to withdraw their reward balance.
     * Anyone can mint a client NFT and start earning rewards, but only approved clients can withdraw.
     * This way the DAO helps mitigate abuse.
     * @dev Only `owner` can call this function
     */
    function setClientApproval(uint32 clientId, bool approved) public onlyOwner {
        RewardsStorage storage $ = _getRewardsStorage();
        $._clientMetadata[clientId].approved = approved;
        emit ClientApprovalSet(clientId, approved);
    }

    /**
     * @notice Updates the auction rewards params
     * @dev Only `owner` can call this function
     */
    function setAuctionRewardParams(AuctionRewardParams calldata newParams) public onlyOwner {
        _getRewardsStorage().auctionRewardParams = newParams;
    }

    /**
     * @notice Enables auction rewards and sets the next auction id to reward to be the current noun on auction
     * @dev Only `owner` can call this function
     */
    function enableAuctionRewards() public onlyOwner {
        RewardsStorage storage $ = _getRewardsStorage();
        uint32 nextAuctionIdToReward = SafeCast.toUint32(auctionHouse.auction().nounId);
        $.nextAuctionIdToReward = nextAuctionIdToReward;
        $.auctionRewardsEnabled = true;

        emit AuctionRewardsEnabled(nextAuctionIdToReward);
    }

    /**
     * @notice Disables auction rewards
     * @dev Only `owner` can call this function
     */
    function disableAuctionRewards() public onlyOwner {
        _getRewardsStorage().auctionRewardsEnabled = false;

        emit AuctionRewardsDisabled();
    }

    /**
     * @notice Updates the proposal rewards params
     * @dev Only `owner` can call this function
     */
    function setProposalRewardParams(ProposalRewardParams calldata newParams) public onlyOwner {
        _getRewardsStorage().proposalRewardParams = newParams;
    }

    /**
     * @notice Enables proposal rewards and sets the next proposal ID to reward to be the next proposal to be created.
     * The first auction ID to be considered for revenue calculation is set to be the current noun in auction.
     * @dev Only `owner` can call this function
     */
    function enableProposalRewards() public onlyOwner {
        RewardsStorage storage $ = _getRewardsStorage();
        uint32 nextProposalIdToReward = SafeCast.toUint32(nounsDAO.proposalCount() + 1);
        uint32 nextProposalRewardFirstAuctionId = SafeCast.toUint32(auctionHouse.auction().nounId);
        $.nextProposalIdToReward = nextProposalIdToReward;
        $.nextProposalRewardFirstAuctionId = nextProposalRewardFirstAuctionId;
        $.lastProposalRewardsUpdate = uint40(block.timestamp);
        $.proposalRewardsEnabled = true;

        emit ProposalRewardsEnabled(nextProposalIdToReward, nextProposalRewardFirstAuctionId);
    }

    /**
     * @notice Disables proposal rewards
     * @dev Only `owner` can call this function
     */
    function disableProposalRewards() public onlyOwner {
        _getRewardsStorage().proposalRewardsEnabled = false;

        emit ProposalRewardsDisabled();
    }

    /**
     * @dev Only `owner` can call this function
     */
    function setAdmin(address newAdmin) public onlyOwner {
        _getRewardsStorage().admin = newAdmin;
    }

    /**
     * @dev Only `owner` can call this function
     */
    function setETHToken(address newToken) public onlyOwner {
        _getRewardsStorage().ethToken = IERC20(newToken);
    }

    /**
     * @notice Withdraws any ERC20 token held by the contract
     * @param token Address of ERC20 token
     * @param to Address to send tokens to
     * @param amount Amount of tokens to withdraw
     * @dev Only `owner` can call this function
     */
    function withdrawToken(address token, address to, uint256 amount) public onlyOwner {
        IERC20(token).safeTransfer(to, amount);
    }

    /**
     * @notice Pauses reward distributes, client registration and withdrawals
     * @dev Only `owner` or `admin` can call this function
     */
    function pause() public onlyOwnerOrAdmin {
        _pause();
    }

    /**
     * @notice Unpauses reward distributes, client registration and withdrawals
     * @dev Only `owner` or `admin` can call this function
     */
    function unpause() public onlyOwnerOrAdmin {
        _unpause();
    }

    /**
     * @notice Set the descriptor for the client token
     * @dev Only `owner` or `admin` can call this function
     */
    function setDescriptor(address descriptor_) public onlyOwnerOrAdmin {
        _getRewardsStorage().descriptor = descriptor_;
    }

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   INTERNAL
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    function sumAuctions(INounsAuctionHouseV2.Settlement[] memory s) internal pure returns (uint256 sum) {
        for (uint256 i = 0; i < s.length; ++i) {
            sum += s[i].amount;
        }
    }

    /**
     * @dev returns true if ids is an array of increasing unique values, i.e. sorted ascending and no duplicates
     */
    function isSortedAndNoDuplicates(uint32[] memory ids) internal pure returns (bool) {
        uint256 len = ids.length;
        uint32 prevValue = ids[0];
        for (uint256 i = 1; i < len; ++i) {
            uint32 nextValue = ids[i];
            if (nextValue <= prevValue) return false;
            prevValue = nextValue;
        }
        return true;
    }

    /**
     * Only `owner` can perform an upgrade
     */
    function _authorizeUpgrade(address) internal view override onlyOwner {}
}

File 2 of 28 : INounsDAOLogic.sol
// SPDX-License-Identifier: GPL-3.0

/// @title Interface for Noun Auction Houses

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.6;

import '../governance/NounsDAOInterfaces.sol';

interface INounsDAOLogic {
    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   PROPOSALS
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */
    /**
     * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold
     * @param targets Target addresses for proposal calls
     * @param values Eth values for proposal calls
     * @param signatures Function signatures for proposal calls
     * @param calldatas Calldatas for proposal calls
     * @param description String description of the proposal
     * @return uint256 Proposal id of new proposal
     */
    function propose(
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory description
    ) external returns (uint256);

    function propose(
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory description,
        uint32 clientId
    ) external returns (uint256);

    /**
     * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold.
     * This proposal would be executed via the timelockV1 contract. This is meant to be used in case timelockV1
     * is still holding funds or has special permissions to execute on certain contracts.
     * @param targets Target addresses for proposal calls
     * @param values Eth values for proposal calls
     * @param signatures Function signatures for proposal calls
     * @param calldatas Calldatas for proposal calls
     * @param description String description of the proposal
     * @return uint256 Proposal id of new proposal
     */
    function proposeOnTimelockV1(
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory description
    ) external returns (uint256);

    function proposeBySigs(
        NounsDAOTypes.ProposerSignature[] memory proposerSignatures,
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory description,
        uint32 clientId
    ) external returns (uint256);

    /**
     * @notice Function used to propose a new proposal. Sender and signers must have delegates above the proposal threshold
     * Signers are regarded as co-proposers, and therefore have the ability to cancel the proposal at any time.
     * @param proposerSignatures Array of signers who have signed the proposal and their signatures.
     * @dev The signatures follow EIP-712. See `PROPOSAL_TYPEHASH` in NounsDAOProposals.sol
     * @param targets Target addresses for proposal calls
     * @param values Eth values for proposal calls
     * @param signatures Function signatures for proposal calls
     * @param calldatas Calldatas for proposal calls
     * @param description String description of the proposal
     * @return uint256 Proposal id of new proposal
     */
    function proposeBySigs(
        NounsDAOTypes.ProposerSignature[] memory proposerSignatures,
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory description
    ) external returns (uint256);

    /**
     * @notice Invalidates a signature that may be used for signing a new proposal.
     * Once a signature is canceled, the sender can no longer use it again.
     * If the sender changes their mind and want to sign the proposal, they can change the expiry timestamp
     * in order to produce a new signature.
     * The signature will only be invalidated when used by the sender. If used by a different account, it will
     * not be invalidated.
     * Cancelling a signature for an existing proposal will have no effect. Signers have the ability to cancel
     * a proposal they signed if necessary.
     * @param sig The signature to cancel
     */
    function cancelSig(bytes calldata sig) external;

    /**
     * @notice Update a proposal transactions and description.
     * Only the proposer can update it, and only during the updateable period.
     * @param proposalId Proposal's id
     * @param targets Updated target addresses for proposal calls
     * @param values Updated eth values for proposal calls
     * @param signatures Updated function signatures for proposal calls
     * @param calldatas Updated calldatas for proposal calls
     * @param description Updated description of the proposal
     * @param updateMessage Short message to explain the update
     */
    function updateProposal(
        uint256 proposalId,
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory description,
        string memory updateMessage
    ) external;

    /**
     * @notice Updates the proposal's description. Only the proposer can update it, and only during the updateable period.
     * @param proposalId Proposal's id
     * @param description Updated description of the proposal
     * @param updateMessage Short message to explain the update
     */
    function updateProposalDescription(
        uint256 proposalId,
        string calldata description,
        string calldata updateMessage
    ) external;

    /**
     * @notice Updates the proposal's transactions. Only the proposer can update it, and only during the updateable period.
     * @param proposalId Proposal's id
     * @param targets Updated target addresses for proposal calls
     * @param values Updated eth values for proposal calls
     * @param signatures Updated function signatures for proposal calls
     * @param calldatas Updated calldatas for proposal calls
     * @param updateMessage Short message to explain the update
     */
    function updateProposalTransactions(
        uint256 proposalId,
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory updateMessage
    ) external;

    /**
     * @notice Update a proposal's transactions and description that was created with proposeBySigs.
     * Only the proposer can update it, during the updateable period.
     * Requires the original signers to sign the update.
     * @param proposalId Proposal's id
     * @param proposerSignatures Array of signers who have signed the proposal and their signatures.
     * @dev The signatures follow EIP-712. See `UPDATE_PROPOSAL_TYPEHASH` in NounsDAOProposals.sol
     * @param targets Updated target addresses for proposal calls
     * @param values Updated eth values for proposal calls
     * @param signatures Updated function signatures for proposal calls
     * @param calldatas Updated calldatas for proposal calls
     * @param description Updated description of the proposal
     * @param updateMessage Short message to explain the update
     */
    function updateProposalBySigs(
        uint256 proposalId,
        NounsDAOTypes.ProposerSignature[] memory proposerSignatures,
        address[] memory targets,
        uint256[] memory values,
        string[] memory signatures,
        bytes[] memory calldatas,
        string memory description,
        string memory updateMessage
    ) external;

    /**
     * @notice Queues a proposal of state succeeded
     * @param proposalId The id of the proposal to queue
     */
    function queue(uint256 proposalId) external;

    /**
     * @notice Executes a queued proposal if eta has passed
     * @param proposalId The id of the proposal to execute
     */
    function execute(uint256 proposalId) external;

    /**
     * @notice Cancels a proposal only if sender is the proposer or a signer, or proposer & signers voting power
     * dropped below proposal threshold
     * @param proposalId The id of the proposal to cancel
     */
    function cancel(uint256 proposalId) external;

    /**
     * @notice Gets the state of a proposal
     * @param proposalId The id of the proposal
     * @return Proposal state
     */
    function state(uint256 proposalId) external view returns (NounsDAOTypes.ProposalState);

    /**
     * @notice Gets actions of a proposal
     * @param proposalId the id of the proposal
     * @return targets
     * @return values
     * @return signatures
     * @return calldatas
     */
    function getActions(
        uint256 proposalId
    )
        external
        view
        returns (
            address[] memory targets,
            uint256[] memory values,
            string[] memory signatures,
            bytes[] memory calldatas
        );

    /**
     * @notice Gets the receipt for a voter on a given proposal
     * @param proposalId the id of proposal
     * @param voter The address of the voter
     * @return The voting receipt
     */
    function getReceipt(uint256 proposalId, address voter) external view returns (NounsDAOTypes.Receipt memory);

    /**
     * @notice Returns the proposal details given a proposal id.
     *     The `quorumVotes` member holds the *current* quorum, given the current votes.
     * @param proposalId the proposal id to get the data for
     * @return A `ProposalCondensed` struct with the proposal data, backwards compatible with V1 and V2
     */
    function proposals(uint256 proposalId) external view returns (NounsDAOTypes.ProposalCondensedV2 memory);

    /**
     * @notice Returns the proposal details given a proposal id.
     *     The `quorumVotes` member holds the *current* quorum, given the current votes.
     * @param proposalId the proposal id to get the data for
     * @return A `ProposalCondensed` struct with the proposal data, not backwards compatible as it contains additional values
     * like `objectionPeriodEndBlock` and `signers`
     */
    function proposalsV3(uint256 proposalId) external view returns (NounsDAOTypes.ProposalCondensedV3 memory);

    function proposalDataForRewards(
        uint256 firstProposalId,
        uint256 lastProposalId,
        uint16 proposalEligibilityQuorumBps,
        bool excludeCanceled,
        bool requireVotingEnded,
        uint32[] calldata votingClientIds
    ) external view returns (NounsDAOTypes.ProposalForRewards[] memory);

    /**
     * @notice Current proposal threshold using Noun Total Supply
     * Differs from `GovernerBravo` which uses fixed amount
     */
    function proposalThreshold() external view returns (uint256);

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   ADMIN
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    /**
     * @notice Admin function for setting the voting delay. Best to set voting delay to at least a few days, to give
     * voters time to make sense of proposals, e.g. 21,600 blocks which should be at least 3 days.
     * @param newVotingDelay new voting delay, in blocks
     */
    function _setVotingDelay(uint256 newVotingDelay) external;

    /**
     * @notice Admin function for setting the voting period
     * @param newVotingPeriod new voting period, in blocks
     */
    function _setVotingPeriod(uint256 newVotingPeriod) external;

    /**
     * @notice Admin function for setting the proposal threshold basis points
     * @dev newProposalThresholdBPS must be in [`MIN_PROPOSAL_THRESHOLD_BPS`,`MAX_PROPOSAL_THRESHOLD_BPS`]
     * @param newProposalThresholdBPS new proposal threshold
     */
    function _setProposalThresholdBPS(uint256 newProposalThresholdBPS) external;

    /**
     * @notice Admin function for setting the objection period duration
     * @param newObjectionPeriodDurationInBlocks new objection period duration, in blocks
     */
    function _setObjectionPeriodDurationInBlocks(uint32 newObjectionPeriodDurationInBlocks) external;

    /**
     * @notice Admin function for setting the objection period last minute window
     * @param newLastMinuteWindowInBlocks new objection period last minute window, in blocks
     */
    function _setLastMinuteWindowInBlocks(uint32 newLastMinuteWindowInBlocks) external;

    /**
     * @notice Admin function for setting the proposal updatable period
     * @param newProposalUpdatablePeriodInBlocks the new proposal updatable period, in blocks
     */
    function _setProposalUpdatablePeriodInBlocks(uint32 newProposalUpdatablePeriodInBlocks) external;

    /**
     * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
     * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
     * @param newPendingAdmin New pending admin.
     */
    function _setPendingAdmin(address newPendingAdmin) external;

    /**
     * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
     * @dev Admin function for pending admin to accept role and update admin
     */
    function _acceptAdmin() external;

    /**
     * @notice Begins transition of vetoer. The newPendingVetoer must call _acceptVetoer to finalize the transfer.
     * @param newPendingVetoer New Pending Vetoer
     */
    function _setPendingVetoer(address newPendingVetoer) external;

    /**
     * @notice Called by the pendingVetoer to accept role and update vetoer
     */
    function _acceptVetoer() external;

    /**
     * @notice Burns veto priviledges
     * @dev Vetoer function destroying veto power forever
     */
    function _burnVetoPower() external;

    /**
     * @notice Admin function for setting the minimum quorum votes bps
     * @param newMinQuorumVotesBPS minimum quorum votes bps
     *     Must be between `MIN_QUORUM_VOTES_BPS_LOWER_BOUND` and `MIN_QUORUM_VOTES_BPS_UPPER_BOUND`
     *     Must be lower than or equal to maxQuorumVotesBPS
     */
    function _setMinQuorumVotesBPS(uint16 newMinQuorumVotesBPS) external;

    /**
     * @notice Admin function for setting the maximum quorum votes bps
     * @param newMaxQuorumVotesBPS maximum quorum votes bps
     *     Must be lower than `MAX_QUORUM_VOTES_BPS_UPPER_BOUND`
     *     Must be higher than or equal to minQuorumVotesBPS
     */
    function _setMaxQuorumVotesBPS(uint16 newMaxQuorumVotesBPS) external;

    /**
     * @notice Admin function for setting the dynamic quorum coefficient
     * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals
     */
    function _setQuorumCoefficient(uint32 newQuorumCoefficient) external;

    /**
     * @notice Admin function for setting all the dynamic quorum parameters
     * @param newMinQuorumVotesBPS minimum quorum votes bps
     *     Must be between `MIN_QUORUM_VOTES_BPS_LOWER_BOUND` and `MIN_QUORUM_VOTES_BPS_UPPER_BOUND`
     *     Must be lower than or equal to maxQuorumVotesBPS
     * @param newMaxQuorumVotesBPS maximum quorum votes bps
     *     Must be lower than `MAX_QUORUM_VOTES_BPS_UPPER_BOUND`
     *     Must be higher than or equal to minQuorumVotesBPS
     * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals
     */
    function _setDynamicQuorumParams(
        uint16 newMinQuorumVotesBPS,
        uint16 newMaxQuorumVotesBPS,
        uint32 newQuorumCoefficient
    ) external;

    /**
     * @notice Withdraws all the ETH in the contract. This is callable only by the admin (timelock).
     */
    function _withdraw() external returns (uint256, bool);

    /**
     * @notice Admin function for setting the fork period
     * @param newForkPeriod the new fork proposal period, in seconds
     */
    function _setForkPeriod(uint256 newForkPeriod) external;

    /**
     * @notice Admin function for setting the fork threshold
     * @param newForkThresholdBPS the new fork proposal threshold, in basis points
     */
    function _setForkThresholdBPS(uint256 newForkThresholdBPS) external;

    /**
     * @notice Admin function for setting the fork DAO deployer contract
     */
    function _setForkDAODeployer(address newForkDAODeployer) external;

    /**
     * @notice Admin function for setting the ERC20 tokens that are used when splitting funds to a fork
     */
    function _setErc20TokensToIncludeInFork(address[] calldata erc20tokens) external;

    /**
     * @notice Admin function for setting the fork escrow contract
     */
    function _setForkEscrow(address newForkEscrow) external;

    /**
     * @notice Admin function for setting the fork related parameters
     * @param forkEscrow_ the fork escrow contract
     * @param forkDAODeployer_ the fork dao deployer contract
     * @param erc20TokensToIncludeInFork_ the ERC20 tokens used when splitting funds to a fork
     * @param forkPeriod_ the period during which it's possible to join a fork after exeuction
     * @param forkThresholdBPS_ the threshold required of escrowed nouns in order to execute a fork
     */
    function _setForkParams(
        address forkEscrow_,
        address forkDAODeployer_,
        address[] calldata erc20TokensToIncludeInFork_,
        uint256 forkPeriod_,
        uint256 forkThresholdBPS_
    ) external;

    /**
     * @notice Admin function for setting the timelocks and admin
     * @param newTimelock the new timelock contract
     * @param newTimelockV1 the new timelockV1 contract
     * @param newAdmin the new admin address
     */
    function _setTimelocksAndAdmin(address newTimelock, address newTimelockV1, address newAdmin) external;

    /**
     * @notice Admin function for zeroing out the state variable `voteSnapshotBlockSwitchProposalId`
     * @dev We want to zero-out this state slot so we can remove this temporary variable from contract code and
     * be ready to reuse this slot.
     */
    function _zeroOutVoteSnapshotBlockSwitchProposalId() external;

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   DYNAMIC QUORUM
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */
    /**
     * @notice Quorum votes required for a specific proposal to succeed
     * Differs from `GovernerBravo` which uses fixed amount
     */
    function quorumVotes(uint256 proposalId) external view returns (uint256);

    /**
     * @notice Calculates the required quorum of for-votes based on the amount of against-votes
     *     The more against-votes there are for a proposal, the higher the required quorum is.
     *     The quorum BPS is between `params.minQuorumVotesBPS` and params.maxQuorumVotesBPS.
     *     The additional quorum is calculated as:
     *       quorumCoefficient * againstVotesBPS
     * @dev Note the coefficient is a fixed point integer with 6 decimals
     * @param againstVotes Number of against-votes in the proposal
     * @param adjustedTotalSupply_ The adjusted total supply of Nouns at the time of proposal creation
     * @param params Configurable parameters for calculating the quorum based on againstVotes. See `DynamicQuorumParams` definition for additional details.
     * @return quorumVotes The required quorum
     */
    function dynamicQuorumVotes(
        uint256 againstVotes,
        uint256 adjustedTotalSupply_,
        NounsDAOTypes.DynamicQuorumParams memory params
    ) external pure returns (uint256);

    /**
     * @notice returns the dynamic quorum parameters values at a certain block number
     * @dev The checkpoints array must not be empty, and the block number must be higher than or equal to
     *     the block of the first checkpoint
     * @param blockNumber_ the block number to get the params at
     * @return The dynamic quorum parameters that were set at the given block number
     */
    function getDynamicQuorumParamsAt(
        uint256 blockNumber_
    ) external view returns (NounsDAOTypes.DynamicQuorumParams memory);

    /**
     * @notice Current min quorum votes using Nouns adjusted total supply
     */
    function minQuorumVotes() external view returns (uint256);

    /**
     * @notice Current max quorum votes using Nouns adjusted total supply
     */
    function maxQuorumVotes() external view returns (uint256);

    /**
     * @notice Get all quorum params checkpoints
     */
    function quorumParamsCheckpoints() external view returns (NounsDAOTypes.DynamicQuorumParamsCheckpoint[] memory);

    /**
     * @notice Get a quorum params checkpoint by its index
     */
    function quorumParamsCheckpoints(
        uint256 index
    ) external view returns (NounsDAOTypes.DynamicQuorumParamsCheckpoint memory);

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   DAO FORK
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    /**
     * @notice Escrow Nouns to contribute to the fork threshold
     * @dev Requires approving the tokenIds or the entire noun token to the DAO contract
     * @param tokenIds the tokenIds to escrow. They will be sent to the DAO once the fork threshold is reached and the escrow is closed.
     * @param proposalIds array of proposal ids which are the reason for wanting to fork. This will only be used to emit event.
     * @param reason the reason for want to fork. This will only be used to emit event.
     */
    function escrowToFork(uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason) external;

    /**
     * @notice Withdraw Nouns from the fork escrow. Only possible if the fork has not been executed.
     * Only allowed to withdraw tokens that the sender has escrowed.
     * @param tokenIds the tokenIds to withdraw
     */
    function withdrawFromForkEscrow(uint256[] calldata tokenIds) external;

    /**
     * @notice Execute the fork. Only possible if the fork threshold has been met.
     * This will deploy a new DAO and send part of the treasury to the new DAO's treasury.
     * This will also close the active escrow and all nouns in the escrow belong to the original DAO.
     * @return forkTreasury The address of the new DAO's treasury
     * @return forkToken The address of the new DAO's token
     */
    function executeFork() external returns (address forkTreasury, address forkToken);

    /**
     * @notice Joins a fork while a fork is active
     * @param tokenIds the tokenIds to send to the DAO in exchange for joining the fork
     * @param proposalIds array of proposal ids which are the reason for wanting to fork. This will only be used to emit event.
     * @param reason the reason for want to fork. This will only be used to emit event.
     */
    function joinFork(uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason) external;

    /**
     * @notice Withdraws nouns from the fork escrow to the treasury after the fork has been executed
     * @dev Only the DAO can call this function
     * @param tokenIds the tokenIds to withdraw
     */
    function withdrawDAONounsFromEscrowToTreasury(uint256[] calldata tokenIds) external;

    /**
     * @notice Withdraws nouns from the fork escrow after the fork has been executed to an address other than the treasury
     * @dev Only the DAO can call this function
     * @param tokenIds the tokenIds to withdraw
     * @param to the address to send the nouns to
     */
    function withdrawDAONounsFromEscrowIncreasingTotalSupply(uint256[] calldata tokenIds, address to) external;

    /**
     * @notice Returns the number of nouns in supply minus nouns owned by the DAO, i.e. held in the treasury or in an
     * escrow after it has closed.
     * This is used when calculating proposal threshold, quorum, fork threshold & treasury split.
     */
    function adjustedTotalSupply() external view returns (uint256);

    /**
     * @notice returns the required number of tokens to escrow to trigger a fork
     */
    function forkThreshold() external view returns (uint256);

    /**
     * @notice Returns the number of tokens currently in escrow, contributing to the fork threshold
     */
    function numTokensInForkEscrow() external view returns (uint256);

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   VOTES
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    /**
     * @notice Vetoes a proposal only if sender is the vetoer and the proposal has not been executed.
     * @param proposalId The id of the proposal to veto
     */
    function veto(uint256 proposalId) external;

    /**
     * @notice Cast a vote for a proposal
     * @param proposalId The id of the proposal to vote on
     * @param support The support value for the vote. 0=against, 1=for, 2=abstain
     */
    function castVote(uint256 proposalId, uint8 support) external;

    function castRefundableVote(uint256 proposalId, uint8 support, uint32 clientId) external;

    /**
     * @notice Cast a vote for a proposal, asking the DAO to refund gas costs.
     * Users with > 0 votes receive refunds. Refunds are partial when using a gas priority fee higher than the DAO's cap.
     * Refunds are partial when the DAO's balance is insufficient.
     * No refund is sent when the DAO's balance is empty. No refund is sent to users with no votes.
     * Voting takes place regardless of refund success.
     * @param proposalId The id of the proposal to vote on
     * @param support The support value for the vote. 0=against, 1=for, 2=abstain
     * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement.
     */
    function castRefundableVote(uint256 proposalId, uint8 support) external;

    function castRefundableVoteWithReason(
        uint256 proposalId,
        uint8 support,
        string calldata reason,
        uint32 clientId
    ) external;

    /**
     * @notice Cast a vote for a proposal, asking the DAO to refund gas costs.
     * Users with > 0 votes receive refunds. Refunds are partial when using a gas priority fee higher than the DAO's cap.
     * Refunds are partial when the DAO's balance is insufficient.
     * No refund is sent when the DAO's balance is empty. No refund is sent to users with no votes.
     * Voting takes place regardless of refund success.
     * @param proposalId The id of the proposal to vote on
     * @param support The support value for the vote. 0=against, 1=for, 2=abstain
     * @param reason The reason given for the vote by the voter
     * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement.
     */
    function castRefundableVoteWithReason(uint256 proposalId, uint8 support, string calldata reason) external;

    /**
     * @notice Cast a vote for a proposal with a reason
     * @param proposalId The id of the proposal to vote on
     * @param support The support value for the vote. 0=against, 1=for, 2=abstain
     * @param reason The reason given for the vote by the voter
     */
    function castVoteWithReason(uint256 proposalId, uint8 support, string calldata reason) external;

    /**
     * @notice Cast a vote for a proposal by signature
     * @dev External function that accepts EIP-712 signatures for voting on proposals.
     */
    function castVoteBySig(uint256 proposalId, uint8 support, uint8 v, bytes32 r, bytes32 s) external;

    /**
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     *   STATE VARIABLE GETTERS
     * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
     */

    function admin() external view returns (address);

    function implementation() external view returns (address);

    function vetoer() external view returns (address);

    function pendingVetoer() external view returns (address);

    function votingDelay() external view returns (uint256);

    function votingPeriod() external view returns (uint256);

    function proposalThresholdBPS() external view returns (uint256);

    function quorumVotesBPS() external view returns (uint256);

    function proposalCount() external view returns (uint256);

    function timelock() external view returns (INounsDAOExecutor);

    function nouns() external view returns (NounsTokenLike);

    function latestProposalIds(address account) external view returns (uint256);

    function lastMinuteWindowInBlocks() external view returns (uint256);

    function objectionPeriodDurationInBlocks() external view returns (uint256);

    function erc20TokensToIncludeInFork() external view returns (address[] memory);

    function forkEscrow() external view returns (INounsDAOForkEscrow);

    function forkDAODeployer() external view returns (IForkDAODeployer);

    function forkEndTimestamp() external view returns (uint256);

    function forkPeriod() external view returns (uint256);

    function forkThresholdBPS() external view returns (uint256);

    function proposalUpdatablePeriodInBlocks() external view returns (uint256);

    function timelockV1() external view returns (address);

    function voteSnapshotBlockSwitchProposalId() external view returns (uint256);
}

// SPDX-License-Identifier: GPL-3.0

/// @title Interface for Noun Auction Houses V2

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.19;

interface INounsAuctionHouseV2 {
    struct AuctionV2 {
        // ID for the Noun (ERC721 token ID)
        uint96 nounId;
        // ID of the client that facilitated the latest bid, used for client rewards
        uint32 clientId;
        // The current highest bid amount
        uint128 amount;
        // The time that the auction started
        uint40 startTime;
        // The time that the auction is scheduled to end
        uint40 endTime;
        // The address of the current highest bid
        address payable bidder;
        // Whether or not the auction has been settled
        bool settled;
    }

    /// @dev We use this struct as the return value of the `auction` function, to maintain backwards compatibility.
    struct AuctionV2View {
        // ID for the Noun (ERC721 token ID)
        uint96 nounId;
        // The current highest bid amount
        uint128 amount;
        // The time that the auction started
        uint40 startTime;
        // The time that the auction is scheduled to end
        uint40 endTime;
        // The address of the current highest bid
        address payable bidder;
        // Whether or not the auction has been settled
        bool settled;
    }

    struct SettlementState {
        // The block.timestamp when the auction was settled.
        uint32 blockTimestamp;
        // The winning bid amount, with 10 decimal places (reducing accuracy to save bits).
        uint64 amount;
        // The address of the auction winner.
        address winner;
        // ID of the client that facilitated the winning bid, used for client rewards.
        uint32 clientId;
        // Used only to warm up the storage slot for clientId without setting the clientId value.
        bool slotWarmedUp;
    }

    struct Settlement {
        // The block.timestamp when the auction was settled.
        uint32 blockTimestamp;
        // The winning bid amount, converted from 10 decimal places to 18, for better client UX.
        uint256 amount;
        // The address of the auction winner.
        address winner;
        // ID for the Noun (ERC721 token ID).
        uint256 nounId;
        // ID of the client that facilitated the winning bid, used for client rewards
        uint32 clientId;
    }

    /// @dev Using this struct when setting historic prices, and excluding clientId to save gas.
    struct SettlementNoClientId {
        // The block.timestamp when the auction was settled.
        uint32 blockTimestamp;
        // The winning bid amount, converted from 10 decimal places to 18, for better client UX.
        uint256 amount;
        // The address of the auction winner.
        address winner;
        // ID for the Noun (ERC721 token ID).
        uint256 nounId;
    }

    event AuctionCreated(uint256 indexed nounId, uint256 startTime, uint256 endTime);

    event AuctionBid(uint256 indexed nounId, address sender, uint256 value, bool extended);

    event AuctionBidWithClientId(uint256 indexed nounId, uint256 value, uint32 indexed clientId);

    event AuctionExtended(uint256 indexed nounId, uint256 endTime);

    event AuctionSettled(uint256 indexed nounId, address winner, uint256 amount);

    event AuctionSettledWithClientId(uint256 indexed nounId, uint32 indexed clientId);

    event AuctionTimeBufferUpdated(uint256 timeBuffer);

    event AuctionReservePriceUpdated(uint256 reservePrice);

    event AuctionMinBidIncrementPercentageUpdated(uint256 minBidIncrementPercentage);

    function settleAuction() external;

    function settleCurrentAndCreateNewAuction() external;

    function createBid(uint256 nounId) external payable;

    function createBid(uint256 nounId, uint32 clientId) external payable;

    function pause() external;

    function unpause() external;

    function setTimeBuffer(uint56 timeBuffer) external;

    function setReservePrice(uint192 reservePrice) external;

    function setMinBidIncrementPercentage(uint8 minBidIncrementPercentage) external;

    function auction() external view returns (AuctionV2View memory);

    function getSettlements(
        uint256 auctionCount,
        bool skipEmptyValues
    ) external view returns (Settlement[] memory settlements);

    function getPrices(uint256 auctionCount) external view returns (uint256[] memory prices);

    function getSettlements(
        uint256 startId,
        uint256 endId,
        bool skipEmptyValues
    ) external view returns (Settlement[] memory settlements);

    function getSettlementsFromIdtoTimestamp(
        uint256 startId,
        uint256 endTimestamp,
        bool skipEmptyValues
    ) external view returns (Settlement[] memory settlements);

    function warmUpSettlementState(uint256 startId, uint256 endId) external;

    function duration() external view returns (uint256);

    function biddingClient(uint256 nounId) external view returns (uint32 clientId);
}

File 4 of 28 : NounsDAOInterfaces.sol
// SPDX-License-Identifier: BSD-3-Clause

/// @title Nouns DAO Logic interfaces and events

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

// LICENSE
// NounsDAOInterfaces.sol is a modified version of Compound Lab's GovernorBravoInterfaces.sol:
// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoInterfaces.sol
//
// GovernorBravoInterfaces.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license.
// With modifications by Nounders DAO.
//
// Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause
//
// MODIFICATIONS
// NounsDAOEvents, NounsDAOProxyStorage, NounsDAOStorageV1 add support for changes made by Nouns DAO to GovernorBravo.sol
// See NounsDAOLogicV1.sol for more details.
// NounsDAOStorageV1Adjusted and NounsDAOStorageV2 add support for a dynamic vote quorum.
// See NounsDAOLogicV2.sol for more details.
// NounsDAOStorageV3
// See NounsDAOLogicV3.sol for more details.

pragma solidity ^0.8.19;

interface NounsDAOEventsV3 {
    /// @notice An event emitted when a new proposal is created
    event ProposalCreated(
        uint256 id,
        address proposer,
        address[] targets,
        uint256[] values,
        string[] signatures,
        bytes[] calldatas,
        uint256 startBlock,
        uint256 endBlock,
        string description
    );

    /// @notice An event emitted when a new proposal is created, which includes additional information
    event ProposalCreatedWithRequirements(
        uint256 id,
        address proposer,
        address[] targets,
        uint256[] values,
        string[] signatures,
        bytes[] calldatas,
        uint256 startBlock,
        uint256 endBlock,
        uint256 proposalThreshold,
        uint256 quorumVotes,
        string description
    );

    /// @notice An event emitted when a vote has been cast on a proposal
    /// @param voter The address which casted a vote
    /// @param proposalId The proposal id which was voted on
    /// @param support Support value for the vote. 0=against, 1=for, 2=abstain
    /// @param votes Number of votes which were cast by the voter
    /// @param reason The reason given for the vote by the voter
    event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 votes, string reason);

    /// @notice An event emitted when a proposal has been canceled
    event ProposalCanceled(uint256 id);

    /// @notice An event emitted when a proposal has been queued in the NounsDAOExecutor
    event ProposalQueued(uint256 id, uint256 eta);

    /// @notice An event emitted when a proposal has been executed in the NounsDAOExecutor
    event ProposalExecuted(uint256 id);

    /// @notice An event emitted when a proposal has been vetoed by vetoAddress
    event ProposalVetoed(uint256 id);

    /// @notice An event emitted when the voting delay is set
    event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay);

    /// @notice An event emitted when the voting period is set
    event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod);

    /// @notice Emitted when proposal threshold basis points is set
    event ProposalThresholdBPSSet(uint256 oldProposalThresholdBPS, uint256 newProposalThresholdBPS);

    /// @notice Emitted when quorum votes basis points is set
    event QuorumVotesBPSSet(uint256 oldQuorumVotesBPS, uint256 newQuorumVotesBPS);

    /// @notice Emitted when pendingAdmin is changed
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /// @notice Emitted when pendingAdmin is accepted, which means admin is updated
    event NewAdmin(address oldAdmin, address newAdmin);

    /// @notice Emitted when vetoer is changed
    event NewVetoer(address oldVetoer, address newVetoer);

    /// @notice Emitted when minQuorumVotesBPS is set
    event MinQuorumVotesBPSSet(uint16 oldMinQuorumVotesBPS, uint16 newMinQuorumVotesBPS);

    /// @notice Emitted when maxQuorumVotesBPS is set
    event MaxQuorumVotesBPSSet(uint16 oldMaxQuorumVotesBPS, uint16 newMaxQuorumVotesBPS);

    /// @notice Emitted when quorumCoefficient is set
    event QuorumCoefficientSet(uint32 oldQuorumCoefficient, uint32 newQuorumCoefficient);

    /// @notice Emitted when a voter cast a vote requesting a gas refund.
    event RefundableVote(address indexed voter, uint256 refundAmount, bool refundSent);

    /// @notice Emitted when admin withdraws the DAO's balance.
    event Withdraw(uint256 amount, bool sent);

    /// @notice Emitted when pendingVetoer is changed
    event NewPendingVetoer(address oldPendingVetoer, address newPendingVetoer);

    /// @notice An event emitted when a new proposal is created, which includes additional information
    /// @dev V3 adds `signers`, `updatePeriodEndBlock` compared to the V1/V2 event.
    /// @dev V4: Removed data that's already emitted in `ProposalCreated`, added clientId
    event ProposalCreatedWithRequirements(
        uint256 id,
        address[] signers,
        uint256 updatePeriodEndBlock,
        uint256 proposalThreshold,
        uint256 quorumVotes,
        uint32 indexed clientId
    );

    /// @notice Emitted when a proposal is created to be executed on timelockV1
    event ProposalCreatedOnTimelockV1(uint256 id);

    /// @notice Emitted when a proposal is updated
    event ProposalUpdated(
        uint256 indexed id,
        address indexed proposer,
        address[] targets,
        uint256[] values,
        string[] signatures,
        bytes[] calldatas,
        string description,
        string updateMessage
    );

    /// @notice Emitted when a proposal's transactions are updated
    event ProposalTransactionsUpdated(
        uint256 indexed id,
        address indexed proposer,
        address[] targets,
        uint256[] values,
        string[] signatures,
        bytes[] calldatas,
        string updateMessage
    );

    /// @notice Emitted when a proposal's description is updated
    event ProposalDescriptionUpdated(
        uint256 indexed id,
        address indexed proposer,
        string description,
        string updateMessage
    );

    /// @notice Emitted when a proposal is set to have an objection period
    event ProposalObjectionPeriodSet(uint256 indexed id, uint256 objectionPeriodEndBlock);

    /// @notice Emitted when someone cancels a signature
    event SignatureCancelled(address indexed signer, bytes sig);

    /// @notice An event emitted when the objection period duration is set
    event ObjectionPeriodDurationSet(
        uint32 oldObjectionPeriodDurationInBlocks,
        uint32 newObjectionPeriodDurationInBlocks
    );

    /// @notice An event emitted when the objection period last minute window is set
    event LastMinuteWindowSet(uint32 oldLastMinuteWindowInBlocks, uint32 newLastMinuteWindowInBlocks);

    /// @notice An event emitted when the proposal updatable period is set
    event ProposalUpdatablePeriodSet(
        uint32 oldProposalUpdatablePeriodInBlocks,
        uint32 newProposalUpdatablePeriodInBlocks
    );

    /// @notice Emitted when the erc20 tokens to include in a fork are set
    event ERC20TokensToIncludeInForkSet(address[] oldErc20Tokens, address[] newErc20tokens);

    /// @notice Emitted when the fork DAO deployer is set
    event ForkDAODeployerSet(address oldForkDAODeployer, address newForkDAODeployer);

    /// @notice Emitted when the during of the forking period is set
    event ForkPeriodSet(uint256 oldForkPeriod, uint256 newForkPeriod);

    /// @notice Emitted when the threhsold for forking is set
    event ForkThresholdSet(uint256 oldForkThreshold, uint256 newForkThreshold);

    /// @notice Emitted when the main timelock, timelockV1 and admin are set
    event TimelocksAndAdminSet(address timelock, address timelockV1, address admin);

    /// @notice Emitted when someones adds nouns to the fork escrow
    event EscrowedToFork(
        uint32 indexed forkId,
        address indexed owner,
        uint256[] tokenIds,
        uint256[] proposalIds,
        string reason
    );

    /// @notice Emitted when the owner withdraws their nouns from the fork escrow
    event WithdrawFromForkEscrow(uint32 indexed forkId, address indexed owner, uint256[] tokenIds);

    /// @notice Emitted when the fork is executed and the forking period begins
    event ExecuteFork(
        uint32 indexed forkId,
        address forkTreasury,
        address forkToken,
        uint256 forkEndTimestamp,
        uint256 tokensInEscrow
    );

    /// @notice Emitted when someone joins a fork during the forking period
    event JoinFork(
        uint32 indexed forkId,
        address indexed owner,
        uint256[] tokenIds,
        uint256[] proposalIds,
        string reason
    );

    /// @notice Emitted when the DAO withdraws nouns from the fork escrow after a fork has been executed
    event DAOWithdrawNounsFromEscrow(uint256[] tokenIds, address to);

    /// @notice Emitted when withdrawing nouns from escrow increases adjusted total supply
    event DAONounsSupplyIncreasedFromEscrow(uint256 numTokens, address to);

    /// @notice An event emitted when a vote has been cast with a non-zero client Id.
    /// @dev Assumes the `VoteCast` event is emitted, and that indexers can use the voter address and propose ID to
    /// find the relevant vote and set its client ID.
    event VoteCastWithClientId(address indexed voter, uint256 indexed proposalId, uint32 indexed clientId);
}

interface INounsDAOExecutor {
    function delay() external view returns (uint256);

    function GRACE_PERIOD() external view returns (uint256);

    function acceptAdmin() external;

    function queuedTransactions(bytes32 hash) external view returns (bool);

    function queueTransaction(
        address target,
        uint256 value,
        string calldata signature,
        bytes calldata data,
        uint256 eta
    ) external returns (bytes32);

    function cancelTransaction(
        address target,
        uint256 value,
        string calldata signature,
        bytes calldata data,
        uint256 eta
    ) external;

    function executeTransaction(
        address target,
        uint256 value,
        string calldata signature,
        bytes calldata data,
        uint256 eta
    ) external payable returns (bytes memory);
}

interface NounsTokenLike {
    function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96);

    function totalSupply() external view returns (uint256);

    function transferFrom(address from, address to, uint256 tokenId) external;

    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function minter() external view returns (address);

    function mint() external returns (uint256);

    function setApprovalForAll(address operator, bool approved) external;
}

interface IForkDAODeployer {
    function deployForkDAO(
        uint256 forkingPeriodEndTimestamp,
        INounsDAOForkEscrow forkEscrowAddress
    ) external returns (address treasury, address token);

    function tokenImpl() external view returns (address);

    function auctionImpl() external view returns (address);

    function governorImpl() external view returns (address);

    function treasuryImpl() external view returns (address);
}

interface INounsDAOExecutorV2 is INounsDAOExecutor {
    function sendETH(address recipient, uint256 ethToSend) external;

    function sendERC20(address recipient, address erc20Token, uint256 tokensToSend) external;
}

interface INounsDAOForkEscrow {
    function markOwner(address owner, uint256[] calldata tokenIds) external;

    function returnTokensToOwner(address owner, uint256[] calldata tokenIds) external;

    function closeEscrow() external returns (uint32);

    function numTokensInEscrow() external view returns (uint256);

    function numTokensOwnedByDAO() external view returns (uint256);

    function withdrawTokens(uint256[] calldata tokenIds, address to) external;

    function forkId() external view returns (uint32);

    function nounsToken() external view returns (NounsTokenLike);

    function dao() external view returns (address);

    function ownerOfEscrowedToken(uint32 forkId_, uint256 tokenId) external view returns (address);
}

interface NounsDAOTypes {
    struct Storage {
        // ================ PROXY ================ //
        /// @notice Administrator for this contract
        address admin;
        /// @notice Pending administrator for this contract
        address pendingAdmin;
        /// @notice Active brains of Governor
        address implementation;
        // ================ V1 ================ //
        /// @notice Vetoer who has the ability to veto any proposal
        address vetoer;
        /// @notice The delay before voting on a proposal may take place, once proposed, in blocks
        uint256 votingDelay;
        /// @notice The duration of voting on a proposal, in blocks
        uint256 votingPeriod;
        /// @notice The basis point number of votes required in order for a voter to become a proposer. *DIFFERS from GovernerBravo
        uint256 proposalThresholdBPS;
        /// @notice The basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. *DIFFERS from GovernerBravo
        uint256 quorumVotesBPS;
        /// @notice The total number of proposals
        uint256 proposalCount;
        /// @notice The address of the Nouns DAO Executor NounsDAOExecutor
        INounsDAOExecutorV2 timelock;
        /// @notice The address of the Nouns tokens
        NounsTokenLike nouns;
        /// @notice The official record of all proposals ever proposed
        mapping(uint256 => Proposal) _proposals;
        /// @notice The latest proposal for each proposer
        mapping(address => uint256) latestProposalIds;
        // ================ V2 ================ //
        DynamicQuorumParamsCheckpoint[] quorumParamsCheckpoints;
        /// @notice Pending new vetoer
        address pendingVetoer;
        // ================ V3 ================ //
        /// @notice user => sig => isCancelled: signatures that have been cancelled by the signer and are no longer valid
        mapping(address => mapping(bytes32 => bool)) cancelledSigs;
        /// @notice The number of blocks before voting ends during which the objection period can be initiated
        uint32 lastMinuteWindowInBlocks;
        /// @notice Length of the objection period in blocks
        uint32 objectionPeriodDurationInBlocks;
        /// @notice Length of proposal updatable period in block
        uint32 proposalUpdatablePeriodInBlocks;
        /// @notice address of the DAO's fork escrow contract
        INounsDAOForkEscrow forkEscrow;
        /// @notice address of the DAO's fork deployer contract
        IForkDAODeployer forkDAODeployer;
        /// @notice ERC20 tokens to include when sending funds to a deployed fork
        address[] erc20TokensToIncludeInFork;
        /// @notice The treasury contract of the last deployed fork
        address forkDAOTreasury;
        /// @notice The token contract of the last deployed fork
        address forkDAOToken;
        /// @notice Timestamp at which the last fork period ends
        uint256 forkEndTimestamp;
        /// @notice Fork period in seconds
        uint256 forkPeriod;
        /// @notice Threshold defined in basis points (10,000 = 100%) required for forking
        uint256 forkThresholdBPS;
        /// @notice Address of the original timelock
        INounsDAOExecutor timelockV1;
        /// @dev Make sure this stays the last variable in this struct, so we can delete it in the next version
        /// @dev To be zeroed-out in the upcoming DAO upgrade.
        uint256 voteSnapshotBlockSwitchProposalId;
    }

    struct Proposal {
        /// @notice Unique id for looking up a proposal
        uint32 id;
        /// @notice client id for rewards
        uint32 clientId;
        /// @notice currently unused
        uint192 _gap;
        /// @notice Creator of the proposal
        address proposer;
        /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo
        uint256 proposalThreshold;
        /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo
        uint256 quorumVotes;
        /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
        uint256 eta;
        /// @notice the ordered list of target addresses for calls to be made
        address[] targets;
        /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made
        uint256[] values;
        /// @notice The ordered list of function signatures to be called
        string[] signatures;
        /// @notice The ordered list of calldata to be passed to each call
        bytes[] calldatas;
        /// @notice The block at which voting begins: holders must delegate their votes prior to this block
        uint256 startBlock;
        /// @notice The block at which voting ends: votes must be cast prior to this block
        uint256 endBlock;
        /// @notice Current number of votes in favor of this proposal
        uint256 forVotes;
        /// @notice Current number of votes in opposition to this proposal
        uint256 againstVotes;
        /// @notice Current number of votes for abstaining for this proposal
        uint256 abstainVotes;
        /// @notice Flag marking whether the proposal has been canceled
        bool canceled;
        /// @notice Flag marking whether the proposal has been vetoed
        bool vetoed;
        /// @notice Flag marking whether the proposal has been executed
        bool executed;
        /// @notice Receipts of ballots for the entire set of voters
        mapping(address => Receipt) receipts;
        /// @notice The total supply at the time of proposal creation
        uint256 totalSupply;
        /// @notice The block at which this proposal was created
        uint32 creationBlock;
        /// @notice The timestamp of the block at which this proposal was created
        uint32 creationTimestamp;
        /// @notice The last block which allows updating a proposal's description and transactions
        uint64 updatePeriodEndBlock;
        /// @notice Starts at 0 and is set to the block at which the objection period ends when the objection period is initiated
        uint64 objectionPeriodEndBlock;
        /// @dev unused for now
        uint64 placeholder;
        /// @notice The signers of a proposal, when using proposeBySigs
        address[] signers;
        /// @notice When true, a proposal would be executed on timelockV1 instead of the current timelock
        bool executeOnTimelockV1;
        /// @notice How many votes and vote transactions each clientId contributed to this proposal
        mapping(uint32 => ClientVoteData) voteClients;
    }

    struct ClientVoteData {
        /// @notice The number of votes the client facilitated on a proposal
        uint32 votes;
        /// @notice The number of vote transactions the client facilitated on a proposal
        uint32 txs;
    }

    /// @notice Ballot receipt record for a voter
    struct Receipt {
        /// @notice Whether or not a vote has been cast
        bool hasVoted;
        /// @notice Whether or not the voter supports the proposal or abstains
        uint8 support;
        /// @notice The number of votes the voter had, which were cast
        uint96 votes;
    }

    struct ProposerSignature {
        /// @notice Signature of a proposal
        bytes sig;
        /// @notice The address of the signer
        address signer;
        /// @notice The timestamp until which the signature is valid
        uint256 expirationTimestamp;
    }

    /// @notice A subset of Proposal data, used for client rewards calculation
    struct ProposalForRewards {
        /// @notice The proposal's voting period end block
        uint256 endBlock;
        /// @notice The proposal's objection period end block
        uint256 objectionPeriodEndBlock;
        /// @notice The proposal's For votes count
        uint256 forVotes;
        /// @notice The proposal's Against votes count
        uint256 againstVotes;
        /// @notice The proposal's Abstain votes count
        uint256 abstainVotes;
        /// @notice The proposal's snapshot of total supply
        uint256 totalSupply;
        /// @notice The timestamp of the block at which the proposal was created
        uint256 creationTimestamp;
        /// @notice The ID for the client that facilitated the proposal
        uint32 clientId;
        ClientVoteData[] voteData;
    }

    struct ProposalCondensedV3 {
        /// @notice Unique id for looking up a proposal
        uint256 id;
        /// @notice Creator of the proposal
        address proposer;
        /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo
        uint256 proposalThreshold;
        /// @notice The minimum number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo
        uint256 quorumVotes;
        /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
        uint256 eta;
        /// @notice The block at which voting begins: holders must delegate their votes prior to this block
        uint256 startBlock;
        /// @notice The block at which voting ends: votes must be cast prior to this block
        uint256 endBlock;
        /// @notice Current number of votes in favor of this proposal
        uint256 forVotes;
        /// @notice Current number of votes in opposition to this proposal
        uint256 againstVotes;
        /// @notice Current number of votes for abstaining for this proposal
        uint256 abstainVotes;
        /// @notice Flag marking whether the proposal has been canceled
        bool canceled;
        /// @notice Flag marking whether the proposal has been vetoed
        bool vetoed;
        /// @notice Flag marking whether the proposal has been executed
        bool executed;
        /// @notice The total supply at the time of proposal creation
        uint256 totalSupply;
        /// @notice The block at which this proposal was created
        uint256 creationBlock;
        /// @notice The signers of a proposal, when using proposeBySigs
        address[] signers;
        /// @notice The last block which allows updating a proposal's description and transactions
        uint256 updatePeriodEndBlock;
        /// @notice Starts at 0 and is set to the block at which the objection period ends when the objection period is initiated
        uint256 objectionPeriodEndBlock;
        /// @notice When true, a proposal would be executed on timelockV1 instead of the current timelock
        bool executeOnTimelockV1;
    }

    struct ProposalCondensedV2 {
        /// @notice Unique id for looking up a proposal
        uint256 id;
        /// @notice Creator of the proposal
        address proposer;
        /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo
        uint256 proposalThreshold;
        /// @notice The minimum number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo
        uint256 quorumVotes;
        /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
        uint256 eta;
        /// @notice The block at which voting begins: holders must delegate their votes prior to this block
        uint256 startBlock;
        /// @notice The block at which voting ends: votes must be cast prior to this block
        uint256 endBlock;
        /// @notice Current number of votes in favor of this proposal
        uint256 forVotes;
        /// @notice Current number of votes in opposition to this proposal
        uint256 againstVotes;
        /// @notice Current number of votes for abstaining for this proposal
        uint256 abstainVotes;
        /// @notice Flag marking whether the proposal has been canceled
        bool canceled;
        /// @notice Flag marking whether the proposal has been vetoed
        bool vetoed;
        /// @notice Flag marking whether the proposal has been executed
        bool executed;
        /// @notice The total supply at the time of proposal creation
        uint256 totalSupply;
        /// @notice The block at which this proposal was created
        uint256 creationBlock;
    }

    struct DynamicQuorumParams {
        /// @notice The minimum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.
        uint16 minQuorumVotesBPS;
        /// @notice The maximum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.
        uint16 maxQuorumVotesBPS;
        /// @notice The dynamic quorum coefficient
        /// @dev Assumed to be fixed point integer with 6 decimals, i.e 0.2 is represented as 0.2 * 1e6 = 200000
        uint32 quorumCoefficient;
    }

    struct NounsDAOParams {
        uint256 votingPeriod;
        uint256 votingDelay;
        uint256 proposalThresholdBPS;
        uint32 lastMinuteWindowInBlocks;
        uint32 objectionPeriodDurationInBlocks;
        uint32 proposalUpdatablePeriodInBlocks;
    }

    /// @notice A checkpoint for storing dynamic quorum params from a given block
    struct DynamicQuorumParamsCheckpoint {
        /// @notice The block at which the new values were set
        uint32 fromBlock;
        /// @notice The parameter values of this checkpoint
        DynamicQuorumParams params;
    }

    /// @notice Possible states that a proposal may be in
    enum ProposalState {
        Pending,
        Active,
        Canceled,
        Defeated,
        Succeeded,
        Queued,
        Expired,
        Executed,
        Vetoed,
        ObjectionPeriod,
        Updatable
    }
}

contract NounsDAOStorage is NounsDAOTypes {
    Storage ds;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal initializer {
        __ERC1967Upgrade_init_unchained();
        __UUPSUpgradeable_init_unchained();
    }

    function __UUPSUpgradeable_init_unchained() internal initializer {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallSecure(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallSecure(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;
    uint256[50] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal initializer {
        __Context_init_unchained();
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal initializer {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
    uint256[49] private __gap;
}

// SPDX-License-Identifier: GPL-3.0

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.19;

/**
 * @notice A library for short lived in memory mappings.
 * This only works when the keys, in this case clientId, are of limited size so that they we can create
 * an array in memory for all the possible values
 */
library ClientRewardsMemoryMapping {
    struct Mapping {
        /// @dev indexes[clientId] returns the index in `values` array where the value for clientId is.
        /// zero means it hasn't been initialized yet.
        uint32[] indexes;
        /// @dev array of values. the first cell (index zero) is kept empty.
        ClientBalance[] values;
        /// @dev index of the next cell in `values` array which we can allocate for a new clientId
        uint32 nextAvailableIndex;
    }

    struct ClientBalance {
        uint32 clientId;
        uint256 balance;
    }

    /**
     * Returns a new in memory mapping.
     * @param maxClientId maximum value for a clientId key
     */
    function createMapping(uint32 maxClientId) internal pure returns (Mapping memory m) {
        m.indexes = new uint32[](maxClientId + 1);
        /// @dev index zero is reserved so allocated one extra cell
        m.values = new ClientBalance[](maxClientId + 2);
        m.nextAvailableIndex = 1; // 0 is reserved to mean unindexed
    }

    /**
     * Sets the value for client `clientId` to `balance`
     */
    function set(Mapping memory m, uint32 clientId, uint256 balance) internal pure {
        uint32 idx = m.indexes[clientId];
        if (idx == 0) {
            idx = m.nextAvailableIndex++;
            m.indexes[clientId] = idx;
            m.values[idx].clientId = clientId;
        }
        m.values[idx].balance = balance;
    }

    /**
     * Increases the value of client `clientId` by `balanceDiff`
     */
    function inc(Mapping memory m, uint32 clientId, uint256 balanceDiff) internal pure {
        uint32 idx = m.indexes[clientId];
        if (idx == 0) {
            idx = m.nextAvailableIndex++;
            m.indexes[clientId] = idx;
            m.values[idx].clientId = clientId;
        }
        m.values[idx].balance += balanceDiff;
    }

    /**
     * Returns the current value for client `clientId`
     */
    function get(Mapping memory m, uint32 clientId) internal pure returns (uint256 balance) {
        uint32 idx = m.indexes[clientId];
        if (idx == 0) return 0;
        return m.values[idx].balance;
    }

    /**
     * Returns the number of key/values stored
     */
    function numValues(Mapping memory m) internal pure returns (uint256) {
        return m.nextAvailableIndex - 1;
    }

    /**
     * Returns the idx-th value stored
     */
    function getValue(Mapping memory m, uint32 idx) internal pure returns (ClientBalance memory) {
        // zero index is unused
        return m.values[idx + 1];
    }
}

// SPDX-License-Identifier: GPL-3.0

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.19;

import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

library GasRefund {
    using SafeERC20 for IERC20;

    /// @notice The maximum priority fee used to cap gas refunds
    uint256 public constant MAX_REFUND_PRIORITY_FEE = 2 gwei;

    /// @notice The vote refund gas overhead, including 7K for token transfer and 29K for general transaction overhead
    uint256 public constant REFUND_BASE_GAS = 36000;

    /// @notice The maximum basefee the DAO will refund
    uint256 public constant MAX_REFUND_BASE_FEE = 200 gwei;

    /// @dev refunds gas using the `ethToken` instead of ETH
    function refundGas(IERC20 ethToken, uint256 startGas) internal {
        unchecked {
            uint256 balance = ethToken.balanceOf(address(this));
            if (balance == 0) {
                return;
            }
            uint256 basefee = min(block.basefee, MAX_REFUND_BASE_FEE);
            uint256 gasPrice = min(tx.gasprice, basefee + MAX_REFUND_PRIORITY_FEE);
            uint256 gasUsed = startGas - gasleft() + REFUND_BASE_GAS;
            uint256 refundAmount = min(gasPrice * gasUsed, balance);
            ethToken.safeTransfer(tx.origin, refundAmount);
        }
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

File 11 of 28 : INounsClientTokenDescriptor.sol
// SPDX-License-Identifier: GPL-3.0

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.19;

import { INounsClientTokenTypes } from './INounsClientTokenTypes.sol';

interface INounsClientTokenDescriptor {
    function tokenURI(
        uint256 tokenId,
        INounsClientTokenTypes.ClientMetadata calldata metadata
    ) external view returns (string memory);
}

File 12 of 28 : INounsClientTokenTypes.sol
// SPDX-License-Identifier: GPL-3.0

/*********************************
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░██░░░████░░██░░░████░░░ *
 * ░░██████░░░████████░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░██░░██░░░████░░██░░░████░░░ *
 * ░░░░░░█████████░░█████████░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
 *********************************/

pragma solidity ^0.8.19;

interface INounsClientTokenTypes {
    struct ClientMetadata {
        /// @notice Whether the DAO has approved the client to withdraw their rewards.
        bool approved;
        /// @notice The amount of reward tokens this client has been rewarded.
        uint96 rewarded;
        /// @notice The amount of tokens this client has withdrawn.
        uint96 withdrawn;
        /// @dev A gap for future storage needs.
        uint56 __gap;
        /// @notice The client's display name.
        string name;
        /// @notice The client's description, e.g. its URL.
        string description;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal initializer {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal initializer {
        _transferOwnership(_msgSender());
    }

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (token/ERC721/ERC721.sol)

pragma solidity ^0.8.0;

import "./IERC721Upgradeable.sol";
import "./IERC721ReceiverUpgradeable.sol";
import "./extensions/IERC721MetadataUpgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../utils/StringsUpgradeable.sol";
import "../../utils/introspection/ERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {
    using AddressUpgradeable for address;
    using StringsUpgradeable for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    function __ERC721_init(string memory name_, string memory symbol_) internal initializer {
        __Context_init_unchained();
        __ERC165_init_unchained();
        __ERC721_init_unchained(name_, symbol_);
    }

    function __ERC721_init_unchained(string memory name_, string memory symbol_) internal initializer {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {
        return
            interfaceId == type(IERC721Upgradeable).interfaceId ||
            interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721Upgradeable.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721Upgradeable.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

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

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721Upgradeable.ownerOf(tokenId);

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

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

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

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits a {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
    uint256[44] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/math/SafeCast.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable {
    function __ERC1967Upgrade_init() internal initializer {
        __ERC1967Upgrade_init_unchained();
    }

    function __ERC1967Upgrade_init_unchained() internal initializer {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallSecure(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        address oldImplementation = _getImplementation();

        // Initial upgrade and setup call
        _setImplementation(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }

        // Perform rollback test if not already in progress
        StorageSlotUpgradeable.BooleanSlot storage rollbackTesting = StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT);
        if (!rollbackTesting.value) {
            // Trigger rollback using upgradeTo from the new implementation
            rollbackTesting.value = true;
            _functionDelegateCall(
                newImplementation,
                abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
            );
            rollbackTesting.value = false;
            // Check rollback was effective
            require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
            // Finally reset to the new implementation and log the upgrade
            _upgradeTo(newImplementation);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }
    uint256[50] private __gap;
}

File 17 of 28 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (proxy/utils/Initializable.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

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

    function __Context_init_unchained() internal initializer {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
    uint256[50] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165Upgradeable.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721Upgradeable is IERC165Upgradeable {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

File 21 of 28 : IERC721ReceiverUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721ReceiverUpgradeable {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721Upgradeable.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721MetadataUpgradeable is IERC721Upgradeable {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal initializer {
        __ERC165_init_unchained();
    }

    function __ERC165_init_unchained() internal initializer {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }
    uint256[50] private __gap;
}

File 26 of 28 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.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 StorageSlotUpgradeable {
    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) {
        assembly {
            r.slot := slot
        }
    }

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "@ensdomains/=../../node_modules/@ensdomains/",
    "@openzeppelin/=../../node_modules/@openzeppelin/",
    "base64-sol/=../../node_modules/base64-sol/",
    "eth-gas-reporter/=../../node_modules/eth-gas-reporter/",
    "hardhat/=../../node_modules/hardhat/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"nounsDAO_","type":"address"},{"internalType":"address","name":"auctionHouse_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"LastNounIdMustBeHigher","type":"error"},{"inputs":[],"name":"LastNounIdMustBeSettled","type":"error"},{"inputs":[],"name":"OnlyNFTOwner","type":"error"},{"inputs":[],"name":"OnlyOwnerOrAdmin","type":"error"},{"inputs":[],"name":"RewardsDisabled","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"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":[],"name":"AuctionRewardsDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"nextAuctionIdToReward","type":"uint32"}],"name":"AuctionRewardsEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"firstAuctionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastAuctionId","type":"uint256"}],"name":"AuctionRewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ClientApprovalSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"ClientBalanceWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"description","type":"string"}],"name":"ClientRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClientRewarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"clientId","type":"uint32"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"description","type":"string"}],"name":"ClientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"ProposalRewardsDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"nextProposalIdToReward","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"nextProposalRewardFirstAuctionId","type":"uint32"}],"name":"ProposalRewardsEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"firstProposalId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"lastProposalId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"firstAuctionIdForRevenue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastAuctionIdForRevenue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"auctionRevenue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerProposal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerVote","type":"uint256"}],"name":"ProposalRewardsUpdated","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":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"RewardsStorageLocation","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"auctionHouse","outputs":[{"internalType":"contract INounsAuctionHouseV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionRewardsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"uint32","name":"clientId","type":"uint32"}],"name":"clientBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"tokenId","type":"uint32"}],"name":"clientMetadata","outputs":[{"components":[{"internalType":"bool","name":"approved","type":"bool"},{"internalType":"uint96","name":"rewarded","type":"uint96"},{"internalType":"uint96","name":"withdrawn","type":"uint96"},{"internalType":"uint56","name":"__gap","type":"uint56"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct INounsClientTokenTypes.ClientMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"descriptor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableAuctionRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableProposalRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableAuctionRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableProposalRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethToken","outputs":[{"internalType":"contract IERC20","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":"firstNounId","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"getAuctionRevenue","outputs":[{"internalType":"uint256","name":"sumRevenue","type":"uint256"},{"internalType":"uint256","name":"lastAuctionId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAuctionRewardParams","outputs":[{"components":[{"internalType":"uint16","name":"auctionRewardBps","type":"uint16"},{"internalType":"uint8","name":"minimumAuctionsBetweenUpdates","type":"uint8"}],"internalType":"struct Rewards.AuctionRewardParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProposalRewardParams","outputs":[{"components":[{"internalType":"uint32","name":"minimumRewardPeriod","type":"uint32"},{"internalType":"uint8","name":"numProposalsEnoughForReward","type":"uint8"},{"internalType":"uint16","name":"proposalRewardBps","type":"uint16"},{"internalType":"uint16","name":"votingRewardBps","type":"uint16"},{"internalType":"uint16","name":"proposalEligibilityQuorumBps","type":"uint16"}],"internalType":"struct Rewards.ProposalRewardParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"lastProposalId","type":"uint32"}],"name":"getVotingClientIds","outputs":[{"internalType":"uint32[]","name":"","type":"uint32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"admin_","type":"address"},{"internalType":"address","name":"ethToken_","type":"address"},{"internalType":"address","name":"descriptor_","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":"lastProposalRewardsUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextAuctionIdToReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextProposalIdToReward","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextProposalRewardFirstAuctionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nounsDAO","outputs":[{"internalType":"contract INounsDAOLogic","name":"","type":"address"}],"stateMutability":"view","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":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalRewardsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"}],"name":"registerClient","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"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":"newAdmin","type":"address"}],"name":"setAdmin","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":[{"components":[{"internalType":"uint16","name":"auctionRewardBps","type":"uint16"},{"internalType":"uint8","name":"minimumAuctionsBetweenUpdates","type":"uint8"}],"internalType":"struct Rewards.AuctionRewardParams","name":"newParams","type":"tuple"}],"name":"setAuctionRewardParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setClientApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"descriptor_","type":"address"}],"name":"setDescriptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newToken","type":"address"}],"name":"setETHToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"minimumRewardPeriod","type":"uint32"},{"internalType":"uint8","name":"numProposalsEnoughForReward","type":"uint8"},{"internalType":"uint16","name":"proposalRewardBps","type":"uint16"},{"internalType":"uint16","name":"votingRewardBps","type":"uint16"},{"internalType":"uint16","name":"proposalEligibilityQuorumBps","type":"uint16"}],"internalType":"struct Rewards.ProposalRewardParams","name":"newParams","type":"tuple"}],"name":"setProposalRewardParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"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":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"}],"name":"updateClientMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"lastNounId","type":"uint32"}],"name":"updateRewardsForAuctions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"lastProposalId","type":"uint32"},{"internalType":"uint32[]","name":"votingClientIds","type":"uint32[]"}],"name":"updateRewardsForProposalWritingAndVoting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"clientId","type":"uint32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"withdrawClientBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e0604052306080523480156200001557600080fd5b50604051620061ad380380620061ad833981016040819052620000389162000129565b600054610100900460ff168062000052575060005460ff16155b620000ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000dd576000805461ffff19166101011790555b6001600160a01b0380841660a052821660c052801562000103576000805461ff00191690555b50505062000161565b80516001600160a01b03811681146200012457600080fd5b919050565b600080604083850312156200013d57600080fd5b62000148836200010c565b915062000158602084016200010c565b90509250929050565b60805160a05160c051615fcf620001de60003960008181610a7a01528181610ce201528181610ef001528181611a2c015261325a0152600081816105a901528181610c49015281816115630152818161280f01526129810152600081816113d50152818161141501528181611d6a0152611daa0152615fcf6000f3fe6080604052600436106103765760003560e01c8063704b6c02116101d1578063ac4951f611610102578063cc9df021116100a0578063ed9152c81161006f578063ed9152c814610a68578063f2fde38b14610a9c578063f851a44014610abc578063f8c8765e14610ad157600080fd5b8063cc9df021146109fe578063d0e1a84614610a1e578063d715d10114610a33578063e985e9c514610a4857600080fd5b8063bce7f0da116100dc578063bce7f0da14610994578063becbeb22146109a9578063c37bb58b146109c9578063c87b56dd146109de57600080fd5b8063ac4951f61461091c578063b289a2bb1461093c578063b88d4fde1461097457600080fd5b80638d9763231161016f57806395d89b411161014957806395d89b411461089b578063a22cb465146108b0578063a412bfbb146108d0578063a556ba311461090757600080fd5b80638d976323146108035780638da5cb5b1461081857806392c6d4201461083657600080fd5b806375794a3c116101ab57806375794a3c146107a45780637bf1a627146107b95780637d15f041146107ce5780638456cb59146107ee57600080fd5b8063704b6c021461074f57806370a082311461076f578063715018a61461078f57600080fd5b8063337344a2116102ab5780634818ac421161024957806354b1faeb1161022357806354b1faeb146106d55780635c975abb146106ea5780635f27663b146107025780636352211e1461072f57600080fd5b80634818ac42146106825780634f1ef286146106a25780634fc8d76a146106b557600080fd5b80633f4ba83a116102855780633f4ba83a146106185780633fabc2521461062d57806342842e0e146106425780634364d9731461066257600080fd5b8063337344a2146105975780633659cfe6146105cb5780633b5003c0146105eb57600080fd5b8063095ea7b31161031857806320e47641116102f257806320e476411461051857806323b872dd146105385780632a72731114610558578063303e74df1461058257600080fd5b8063095ea7b31461049657806317cb7292146104b65780631ac8875d146104d657600080fd5b80630553d778116103545780630553d778146103f257806306fdde031461040757806307d7461e14610429578063081812fc1461045e57600080fd5b806301b9a3971461037b57806301e336671461039d57806301ffc9a7146103bd575b600080fd5b34801561038757600080fd5b5061039b610396366004614a6b565b610af1565b005b3480156103a957600080fd5b5061039b6103b8366004614a88565b610b6e565b3480156103c957600080fd5b506103dd6103d8366004614adf565b610bba565b60405190151581526020015b60405180910390f35b3480156103fe57600080fd5b5061039b610c0c565b34801561041357600080fd5b5061041c610e2a565b6040516103e99190614b4c565b34801561043557600080fd5b50610449610444366004614b5f565b610ebd565b604080519283526020830191909152016103e9565b34801561046a57600080fd5b5061047e610479366004614b81565b610fa1565b6040516001600160a01b0390911681526020016103e9565b3480156104a257600080fd5b5061039b6104b1366004614b9a565b611038565b3480156104c257600080fd5b5061039b6104d1366004614bc6565b611148565b3480156104e257600080fd5b5061050a7f9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd70081565b6040519081526020016103e9565b34801561052457600080fd5b5061039b610533366004614bff565b611188565b34801561054457600080fd5b5061039b610553366004614a88565b611361565b34801561056457600080fd5b5061056d611392565b60405163ffffffff90911681526020016103e9565b34801561058e57600080fd5b5061047e6113af565b3480156105a357600080fd5b5061047e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156105d757600080fd5b5061039b6105e6366004614a6b565b6113cb565b3480156105f757600080fd5b5061060b610606366004614c4a565b611493565b6040516103e99190614ca9565b34801561062457600080fd5b5061039b6117c0565b34801561063957600080fd5b5061050a611817565b34801561064e57600080fd5b5061039b61065d366004614a88565b611834565b34801561066e57600080fd5b5061056d61067d366004614d04565b61184f565b34801561068e57600080fd5b5061039b61069d366004614c4a565b611943565b61039b6106b0366004614e9f565b611d60565b3480156106c157600080fd5b5061039b6106d0366004614eee565b611e19565b3480156106e157600080fd5b5061050a611e59565b3480156106f657600080fd5b5060975460ff166103dd565b34801561070e57600080fd5b5061072261071d366004614c4a565b611e76565b6040516103e99190614f00565b34801561073b57600080fd5b5061047e61074a366004614b81565b61204f565b34801561075b57600080fd5b5061039b61076a366004614a6b565b6120c7565b34801561077b57600080fd5b5061050a61078a366004614a6b565b61211e565b34801561079b57600080fd5b5061039b6121a6565b3480156107b057600080fd5b5061056d6121dc565b3480156107c557600080fd5b5061047e6121f2565b3480156107da57600080fd5b5061039b6107e9366004614a6b565b61220e565b3480156107fa57600080fd5b5061039b612265565b34801561080f57600080fd5b5061039b6122bc565b34801561082457600080fd5b5060c9546001600160a01b031661047e565b34801561084257600080fd5b5061084b612337565b60408051825163ffffffff16815260208084015160ff16908201528282015161ffff908116928201929092526060808401518316908201526080928301519091169181019190915260a0016103e9565b3480156108a757600080fd5b5061041c6123c7565b3480156108bc57600080fd5b5061039b6108cb366004614f89565b6123d7565b3480156108dc57600080fd5b506108e56123e2565b60408051825161ffff16815260209283015160ff1692810192909252016103e9565b34801561091357600080fd5b506103dd612429565b34801561092857600080fd5b5061039b610937366004614fc2565b612444565b34801561094857600080fd5b5061095c610957366004614c4a565b6124e2565b6040516001600160601b0390911681526020016103e9565b34801561098057600080fd5b5061039b61098f366004614fe0565b61252b565b3480156109a057600080fd5b5061039b612563565b3480156109b557600080fd5b5061039b6109c436600461504b565b6125dc565b3480156109d557600080fd5b506103dd6126a3565b3480156109ea57600080fd5b5061041c6109f9366004614b81565b6126bd565b348015610a0a57600080fd5b5061039b610a193660046150cd565b612763565b348015610a2a57600080fd5b5061039b61321d565b348015610a3f57600080fd5b5061050a613330565b348015610a5457600080fd5b506103dd610a63366004615154565b61334e565b348015610a7457600080fd5b5061047e7f000000000000000000000000000000000000000000000000000000000000000081565b348015610aa857600080fd5b5061039b610ab7366004614a6b565b61337d565b348015610ac857600080fd5b5061047e613415565b348015610add57600080fd5b5061039b610aec366004615182565b613431565b6000610afb613564565b60c9549091506001600160a01b0316331480610b23575060048101546001600160a01b031633145b610b4057604051636f0cab8b60e11b815260040160405180910390fd5b81610b49613564565b60060180546001600160a01b0319166001600160a01b03929092169190911790555050565b60c9546001600160a01b03163314610ba15760405162461bcd60e51b8152600401610b98906151de565b60405180910390fd5b610bb56001600160a01b0384168383613588565b505050565b60006001600160e01b031982166380ac58cd60e01b1480610beb57506001600160e01b03198216635b5e139f60e01b145b80610c0657506301ffc9a760e01b6001600160e01b03198316145b92915050565b60c9546001600160a01b03163314610c365760405162461bcd60e51b8152600401610b98906151de565b6000610c40613564565b90506000610cd97f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663da35c6646040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc99190615213565b610cd4906001615242565b6135da565b90506000610d717f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637d9f6db56040518163ffffffff1660e01b815260040160c060405180830381865afa158015610d3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d62919061527a565b516001600160601b03166135da565b8354600160481b67ffffffffffffffff60501b19909116600160501b63ffffffff86811691820263ffffffff60701b191692909217600160701b9285169283021776ffffffffff0000000000000000ff0000000000000000001916600160901b4264ffffffffff160260ff60481b1916179290921786556040805192835260208301919091529192507fda1b197b06385756fea2566b6b617ea13d1b3d772596d5e7ad6651385ef7acf7910160405180910390a1505050565b606061012d8054610e3a90615333565b80601f0160208091040260200160405190810160405280929190818152602001828054610e6690615333565b8015610eb35780601f10610e8857610100808354040283529160200191610eb3565b820191906000526020600020905b815481529060010190602001808311610e9657829003601f168201915b5050505050905090565b6040516309b8570960e01b8152600481018390526024810182905260016044820152600090819081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309b8570990606401600060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f5f9190810190615395565b9050610f6a81613643565b92508060018251610f7b9190615481565b81518110610f8b57610f8b615494565b6020026020010151606001519150509250929050565b600081815261012f60205260408120546001600160a01b031661101b5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b98565b50600090815261013160205260409020546001600160a01b031690565b60006110438261204f565b9050806001600160a01b0316836001600160a01b0316036110b05760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610b98565b336001600160a01b03821614806110cc57506110cc813361334e565b61113e5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b98565b610bb58383613689565b60c9546001600160a01b031633146111725760405162461bcd60e51b8152600401610b98906151de565b8061117b613564565b600201610bb582826154d1565b60975460ff16156111ab5760405162461bcd60e51b8152600401610b9890615510565b60006111b5613564565b63ffffffff85166000818152600583016020526040902091925033906111da9061204f565b6001600160a01b03161461120157604051636a45792360e11b815260040160405180910390fd5b805460ff166112415760405162461bcd60e51b815260206004820152600c60248201526b1b9bdd08185c1c1c9bdd995960a21b6044820152606401610b98565b80546001600160601b03600160681b820481169161126691839161010090041661553a565b6001600160601b0316846001600160601b031611156112ba5760405162461bcd60e51b815260206004820152601060248201526f616d6f756e7420746f6f206c6172676560801b6044820152606401610b98565b6112c48482615561565b82546bffffffffffffffffffffffff60681b1916600160681b6001600160601b03928316021783556040805191861682526001600160a01b038716602083015263ffffffff8816917f1812827f1c6a24a5651bf4de08620620edf7827369871a784625bf0ad118f120910160405180910390a26003830154611359906001600160a01b0316866001600160601b038716613588565b505050505050565b61136b33826136f8565b6113875760405162461bcd60e51b8152600401610b9890615581565b610bb58383836137c8565b600061139c613564565b54600160501b900463ffffffff16919050565b60006113b9613564565b600601546001600160a01b0316919050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036114135760405162461bcd60e51b8152600401610b98906155d2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661144561396b565b6001600160a01b03161461146b5760405162461bcd60e51b8152600401610b989061561e565b61147481613999565b60408051600080825260208201909252611490918391906139c3565b50565b6060600061149f613564565b905060006114ab6121dc565b63ffffffff1690506000816001600160401b038111156114cd576114cd614d6f565b6040519080825280602002602001820160405280156114f6578160200160208202803683370190505b50905060005b828163ffffffff1610156115485780828263ffffffff168151811061152357611523615494565b63ffffffff909216602092830291909101909101526115418161566a565b90506114fc565b50825460018085015460405163aa0e23c760e01b81526000937f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169363aa0e23c7936115c193600160501b90930463ffffffff16928c92600160481b90920461ffff16919081908a9060040161568d565b600060405180830381865afa1580156115de573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116069190810190615778565b90506000836001600160401b0381111561162257611622614d6f565b60405190808252806020026020018201604052801561164b578160200160208202803683370190505b50905060005b82518110156116e15760005b858110156116d85783828151811061167757611677615494565b60200260200101516101000151818151811061169557611695615494565b6020026020010151600001518382815181106116b3576116b3615494565b602002602001018181516116c791906158bd565b63ffffffff1690525060010161165d565b50600101611651565b50600080856001600160401b038111156116fd576116fd614d6f565b604051908082528060200260200182016040528015611726578160200160208202803683370190505b50905060005b868163ffffffff1610156117b1576000848263ffffffff168151811061175457611754615494565b602002602001015163ffffffff1611156117a157808284611774816158da565b95508151811061178657611786615494565b602002602001019063ffffffff16908163ffffffff16815250505b6117aa8161566a565b905061172c565b50908152979650505050505050565b60006117ca613564565b60c9549091506001600160a01b03163314806117f2575060048101546001600160a01b031633145b61180f57604051636f0cab8b60e11b815260040160405180910390fd5b611490613b07565b6000611821613564565b54600160281b900463ffffffff16919050565b610bb58383836040518060200160405280600081525061252b565b600061185d60975460ff1690565b1561187a5760405162461bcd60e51b8152600401610b9890615510565b6000611884613564565b805490915063ffffffff1661189a8160016158bd565b825463ffffffff191663ffffffff9182161783556118bb9033908316613b9a565b63ffffffff811660009081526005830160205260409020600181016118e1888a8361593b565b50600281016118f186888361593b565b508163ffffffff167f65beab8930287623c694d7e645cdd4b7b83bebaaac913f30933d4c691a271e3c8989898960405161192e9493929190615a23565b60405180910390a2509150505b949350505050565b60975460ff16156119665760405162461bcd60e51b8152600401610b9890615510565b60005a90506000611975613564565b8054909150640100000000900460ff166119a2576040516333d63cbd60e01b815260040160405180910390fd5b80546002820154600091600160281b900463ffffffff16906119cd9062010000900460ff1682615242565b8563ffffffff1610156119f35760405163268bc0ad60e01b815260040160405180910390fd5b6119fe8560016158bd565b835463ffffffff91909116600160281b0268ffffffff00000000001990911617835560006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663b1296a9483611a5d8960016158bd565b6040516001600160e01b031960e085901b168152600481019290925263ffffffff16602482015260016044820152606401600060405180830381865afa158015611aab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ad39190810190615395565b905060008160018351611ae69190615481565b81518110611af657611af6615494565b602002602001015190508663ffffffff168160600151148015611b2357506001816000015163ffffffff16115b611b40576040516368752cd160e01b815260040160405180910390fd5b60006001611b4c6121dc565b611b569190615a4a565b90506000611b6382613cdf565b905060005b8451811015611be1576000858281518110611b8557611b85615494565b60200260200101519050806080015163ffffffff16600014158015611bba57508363ffffffff16816080015163ffffffff1611155b15611bd8576080810151602082015160019950611bd8918591613dce565b50600101611b68565b50600287015461ffff166000611bf683613ecd565b905060005b818163ffffffff161015611cf6576000611c158583613eec565b905060006127108561ffff168360200151611c309190615a67565b611c3a9190615a7e565b9050611c4581613f36565b825163ffffffff16600090815260058e01602052604090208054600190611c7b90849061010090046001600160601b0316615561565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550816000015163ffffffff167f8a6390ffb12581558b6798514e694cb23b44ff553c82d4e69024ab1fe2230ae282604051611cdb91815260200190565b60405180910390a2505080611cef9061566a565b9050611bfb565b506040805188815263ffffffff8d1660208201527ff48a534da18c3b27deb2da48e4a2d8b1888ad5cb761889d25b692de9da944d22910160405180910390a18715611d53576003890154611d53906001600160a01b03168b613f9e565b5050505050505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611da85760405162461bcd60e51b8152600401610b98906155d2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611dda61396b565b6001600160a01b031614611e005760405162461bcd60e51b8152600401610b989061561e565b611e0982613999565b611e15828260016139c3565b5050565b60c9546001600160a01b03163314611e435760405162461bcd60e51b8152600401610b98906151de565b80611e4c613564565b600101610bb58282615aa0565b6000611e63613564565b54600160701b900463ffffffff16919050565b6040805160c0810182526000808252602082018190529181018290526060808201929092526080810182905260a0810191909152611eb2613564565b63ffffffff831660009081526005919091016020908152604091829020825160c081018452815460ff81161515825261010081046001600160601b0390811694830194909452600160681b810490931693810193909352600160c81b90910466ffffffffffffff166060830152600181018054608084019190611f3490615333565b80601f0160208091040260200160405190810160405280929190818152602001828054611f6090615333565b8015611fad5780601f10611f8257610100808354040283529160200191611fad565b820191906000526020600020905b815481529060010190602001808311611f9057829003601f168201915b50505050508152602001600282018054611fc690615333565b80601f0160208091040260200160405190810160405280929190818152602001828054611ff290615333565b801561203f5780601f106120145761010080835404028352916020019161203f565b820191906000526020600020905b81548152906001019060200180831161202257829003601f168201915b5050505050815250509050919050565b600081815261012f60205260408120546001600160a01b031680610c065760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610b98565b60c9546001600160a01b031633146120f15760405162461bcd60e51b8152600401610b98906151de565b806120fa613564565b60040180546001600160a01b0319166001600160a01b039290921691909117905550565b60006001600160a01b0382166121895760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610b98565b506001600160a01b03166000908152610130602052604090205490565b60c9546001600160a01b031633146121d05760405162461bcd60e51b8152600401610b98906151de565b6121da6000614077565b565b60006121e6613564565b5463ffffffff16919050565b60006121fc613564565b600301546001600160a01b0316919050565b60c9546001600160a01b031633146122385760405162461bcd60e51b8152600401610b98906151de565b80612241613564565b60030180546001600160a01b0319166001600160a01b039290921691909117905550565b600061226f613564565b60c9549091506001600160a01b0316331480612297575060048101546001600160a01b031633145b6122b457604051636f0cab8b60e11b815260040160405180910390fd5b6114906140c9565b60c9546001600160a01b031633146122e65760405162461bcd60e51b8152600401610b98906151de565b60006122f0613564565b80549115156401000000000264ff00000000199092169190911790556040517f2b6b9a9cec683ce4fb9078fe61298719dcfeb0c26e7217bc748101cd3994367590600090a1565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261236a613564565b6040805160a0810182526001929092015463ffffffff8116835260ff640100000000820416602084015261ffff600160281b8204811692840192909252600160381b810482166060840152600160481b9004166080820152919050565b606061012e8054610e3a90615333565b611e15338383614121565b60408051808201909152600080825260208201526123fe613564565b604080518082019091526002919091015461ffff8116825262010000900460ff166020820152919050565b6000612433613564565b54640100000000900460ff16919050565b60c9546001600160a01b0316331461246e5760405162461bcd60e51b8152600401610b98906151de565b6000612478613564565b63ffffffff8416600081815260058301602052604090819020805486151560ff1990911617905551919250907f0f437477476c892b5eab47c4de7c7b038039c74ddde189b97d3315378149d7cb906124d590851515815260200190565b60405180910390a2505050565b6000806124ed613564565b63ffffffff84166000908152600582016020526040902080549192509061193b906001600160601b03600160681b820481169161010090041661553a565b61253533836136f8565b6125515760405162461bcd60e51b8152600401610b9890615581565b61255d848484846141f0565b50505050565b60c9546001600160a01b0316331461258d5760405162461bcd60e51b8152600401610b98906151de565b6000612597613564565b8054911515600160481b0260ff60481b199092169190911790556040517f59a08195999a8f63cd06ccede81a2f98993507dd88f42e1cc630e3df00a1534590600090a1565b60006125e6613564565b9050336125f863ffffffff881661204f565b6001600160a01b03161461261f57604051636a45792360e11b815260040160405180910390fd5b63ffffffff8616600090815260058201602052604090206001810161264586888361593b565b506002810161265584868361593b565b508663ffffffff167f0bee293e8de088ced65538b9072d95ce36471240b1de1e8193ab5e9391294583878787876040516126929493929190615a23565b60405180910390a250505050505050565b60006126ad613564565b54600160481b900460ff16919050565b606060006126c9613564565b600681015463ffffffff85166000908152600583016020526040908190209051635fa2601560e01b81529293506001600160a01b0390911691635fa260159161271791879190600401615bf3565b600060405180830381865afa158015612734573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261275c9190810190615c72565b9392505050565b60975460ff16156127865760405162461bcd60e51b8152600401610b9890615510565b60005a90506000612795613564565b8054909150600160481b900460ff166127c1576040516333d63cbd60e01b815260040160405180910390fd5b6127c96149b9565b60016127d36121dc565b6127dd9190615a4a565b63ffffffff908116825282546040805163368d719960e21b81529051600160501b909204909216916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163da35c664916004808201926020929091908290030181865afa15801561285b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287f9190615213565b8763ffffffff16111580156128a057508063ffffffff168763ffffffff1610155b6128e15760405162461bcd60e51b8152602060048201526012602482015271189859081b185cdd141c9bdc1bdcd85b125960721b6044820152606401610b98565b61291d86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061422392505050565b6129695760405162461bcd60e51b815260206004820152601760248201527f6d75737420626520736f72746564202620756e697175650000000000000000006044820152606401610b98565b60018381015460405163aa0e23c760e01b81526000927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169263aa0e23c7926129d49287928e92600160481b90910461ffff16919081908f908f90600401615cdf565b600060405180830381865afa1580156129f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a199190810190615778565b90506000815111612a6c5760405162461bcd60e51b815260206004820152601e60248201527f6174206c65617374206f6e6520656c696769626c652070726f706f73616c00006044820152606401610b98565b612a778860016158bd565b845463ffffffff91909116600160501b0263ffffffff60501b1990911617845580518190612aa790600190615481565b81518110612ab757612ab7615494565b602090810291909101015160e084018190528454600160701b900463ffffffff1660c0808601829052909101516000918291612af39190610ebd565b9092509050612b038160016158bd565b865463ffffffff91909116600160701b0263ffffffff60701b1990911617865581612b705760405162461bcd60e51b815260206004820152601a60248201527f61756374696f6e526576656e7565206d757374206265203e20300000000000006044820152606401610b98565b600186015461271090612b8e90600160281b900461ffff1684615a67565b612b989190615a7e565b6080860152600186015461271090612bbb90600160381b900461ffff1684615a67565b612bc59190615a7e565b60a086015260005b8351811015612c66576000848281518110612bea57612bea615494565b602002602001015160800151858381518110612c0857612c08615494565b602002602001015160600151868481518110612c2657612c26615494565b602002602001015160400151612c3c9190615242565b612c469190615242565b90508087602001818151612c5a9190615242565b90525050600101612bcd565b506001860154835164010000000090910460ff161115612cfb5760018601548654612ca59163ffffffff1690600160901b900464ffffffffff16615d62565b64ffffffffff168560e0015160c0015111612cfb5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08195b9bdd59da081d1a5b59481c185cdcd95960521b6044820152606401610b98565b60e085015160c00151865464ffffffffff909116600160901b0264ffffffffff60901b1990911617865582516080860151612d369190615a7e565b6040860152602085015160a0860151612d4f9190615a7e565b8560600181815250507fb3719109848cd6df9b4ff39633f0b408e8595e8415ec7bc319800ab3a9dba95d848b8760c0015184868a604001518b60600151604051612dd5979695949392919063ffffffff978816815295909616602086015260408501939093526060840191909152608083015260a082015260c081019190915260e00190565b60405180910390a16000612dec8660000151613cdf565b90506000896001600160401b03811115612e0857612e08614d6f565b604051908082528060200260200182016040528015612e31578160200160208202803683370190505b50905060005b855181101561308d576000868281518110612e5457612e54615494565b602002602001015160e0015190508063ffffffff16600014158015612e895750886000015163ffffffff168163ffffffff1611155b15612ea0576040890151612ea09085908390613dce565b600080888481518110612eb557612eb5615494565b60200260200101516101000151905060005b8e811015612fc2578f8f82818110612ee157612ee1615494565b9050602002016020810190612ef69190614c4a565b93506000828281518110612f0c57612f0c615494565b60200260200101516000015163ffffffff169050868281518110612f3257612f32615494565b602002602001015180612f455750600081115b878381518110612f5757612f57615494565b9115156020928302919091019091015263ffffffff851615801590612f8c57508c6000015163ffffffff168563ffffffff1611155b15612fad57612fad858e6060015183612fa59190615a67565b8a9190613dce565b612fb78185615242565b935050600101612ec7565b50888481518110612fd557612fd5615494565b602002602001015160800151898581518110612ff357612ff3615494565b6020026020010151606001518a868151811061301157613011615494565b6020026020010151604001516130279190615242565b6130319190615242565b821461307f5760405162461bcd60e51b815260206004820152601760248201527f6e6f7420616c6c20766f746573206163636f756e7465640000000000000000006044820152606401610b98565b505050806001019050612e37565b5060005b8151811015613108578181815181106130ac576130ac615494565b60200260200101516131005760405162461bcd60e51b815260206004820152601c60248201527f616c6c20636c69656e744964206d757374206861766520766f746573000000006044820152606401610b98565b600101613091565b50600061311483613ecd565b905060005b818163ffffffff1610156131f55760006131338583613eec565b90506131428160200151613f36565b815163ffffffff16600090815260058d0160205260409020805460019061317890849061010090046001600160601b0316615561565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550806000015163ffffffff167f8a6390ffb12581558b6798514e694cb23b44ff553c82d4e69024ab1fe2230ae282602001516040516131dc91815260200190565b60405180910390a2506131ee8161566a565b9050613119565b50600389015461320e906001600160a01b03168b613f9e565b50505050505050505050505050565b60c9546001600160a01b031633146132475760405162461bcd60e51b8152600401610b98906151de565b6000613251613564565b905060006132b67f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637d9f6db56040518163ffffffff1660e01b815260040160c060405180830381865afa158015610d3e573d6000803e3d6000fd5b825464ff000000001963ffffffff8316600160281b021668ffffffffff0000000019909116176401000000001783556040519091507f8157ff66129c00501479a49058e6c0b2f966c1e797fbb240812faa57ad5b68679061332490839063ffffffff91909116815260200190565b60405180910390a15050565b600061333a613564565b54600160901b900464ffffffffff16919050565b6001600160a01b0391821660009081526101326020908152604080832093909416825291909152205460ff1690565b60c9546001600160a01b031633146133a75760405162461bcd60e51b8152600401610b98906151de565b6001600160a01b03811661340c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b98565b61149081614077565b600061341f613564565b600401546001600160a01b0316919050565b600054610100900460ff168061344a575060005460ff16155b6134665760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff16158015613488576000805461ffff19166101011790555b6134906142a3565b6134e7604051806040016040528060128152602001712737bab7399021b634b2b73a102a37b5b2b760711b8152506040518060400160405280600b81526020016a1393d55394d0d31251539560aa1b815250614318565b60006134f1613564565b805463ffffffff19166001178155905061350a86614077565b6004810180546001600160a01b038088166001600160a01b0319928316179092556003830180548784169083161790556006909201805491851691909216179055801561355d576000805461ff00191690555b5050505050565b7f9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd70090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610bb590849061439f565b600063ffffffff82111561363f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610b98565b5090565b6000805b82518110156136835782818151811061366257613662615494565b602002602001015160200151826136799190615242565b9150600101613647565b50919050565b60008181526101316020526040902080546001600160a01b0319166001600160a01b03841690811790915581906136bf8261204f565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600081815261012f60205260408120546001600160a01b03166137725760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b98565b600061377d8361204f565b9050806001600160a01b0316846001600160a01b031614806137b85750836001600160a01b03166137ad84610fa1565b6001600160a01b0316145b8061193b575061193b818561334e565b826001600160a01b03166137db8261204f565b6001600160a01b0316146138435760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610b98565b6001600160a01b0382166138a55760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610b98565b6138b0600082613689565b6001600160a01b0383166000908152610130602052604081208054600192906138da908490615481565b90915550506001600160a01b038216600090815261013060205260408120805460019290613909908490615242565b9091555050600081815261012f602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60c9546001600160a01b031633146114905760405162461bcd60e51b8152600401610b98906151de565b60006139cd61396b565b90506139d884614471565b6000835111806139e55750815b156139f6576139f48484614516565b505b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143805460ff1661355d57805460ff191660011781556040516001600160a01b0383166024820152613a7590869060440160408051601f198184030181529190526020810180516001600160e01b0316631b2ce7f360e11b179052614516565b50805460ff19168155613a8661396b565b6001600160a01b0316826001600160a01b031614613afe5760405162461bcd60e51b815260206004820152602f60248201527f45524331393637557067726164653a207570677261646520627265616b73206660448201526e75727468657220757067726164657360881b6064820152608401610b98565b61355d85614601565b60975460ff16613b505760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610b98565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216613bf05760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b98565b600081815261012f60205260409020546001600160a01b031615613c565760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b98565b6001600160a01b038216600090815261013060205260408120805460019290613c80908490615242565b9091555050600081815261012f602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60408051606080820183528082526020820152600091810191909152613d068260016158bd565b63ffffffff166001600160401b03811115613d2357613d23614d6f565b604051908082528060200260200182016040528015613d4c578160200160208202803683370190505b508152613d5a8260026158bd565b63ffffffff166001600160401b03811115613d7757613d77614d6f565b604051908082528060200260200182016040528015613dbc57816020015b6040805180820190915260008082526020820152815260200190600190039081613d955790505b50602082015260016040820152919050565b600083600001518363ffffffff1681518110613dec57613dec615494565b602002602001015190508063ffffffff16600003613e8f5760408401805190613e148261566a565b63ffffffff1663ffffffff1681525090508084600001518463ffffffff1681518110613e4257613e42615494565b602002602001019063ffffffff16908163ffffffff16815250508284602001518263ffffffff1681518110613e7957613e79615494565b602090810291909101015163ffffffff90911690525b8184602001518263ffffffff1681518110613eac57613eac615494565b6020026020010151602001818151613ec49190615242565b90525050505050565b600060018260400151613ee09190615a4a565b63ffffffff1692915050565b60408051808201909152600080825260208201526020830151613f108360016158bd565b63ffffffff1681518110613f2657613f26615494565b6020026020010151905092915050565b60006001600160601b0382111561363f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b6064820152608401610b98565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015613fe5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140099190615213565b90508060000361401857505050565b600061402948642e90edd000614641565b9050600061403d3a63773594008401614641565b90506000618ca05a8603019050600061405882840286614641565b905061406e6001600160a01b0388163283613588565b50505050505050565b60c980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60975460ff16156140ec5760405162461bcd60e51b8152600401610b9890615510565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613b7d3390565b816001600160a01b0316836001600160a01b0316036141825760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b98565b6001600160a01b0383811660008181526101326020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6141fb8484846137c8565b61420784848484614657565b61255d5760405162461bcd60e51b8152600401610b9890615dce565b80516000908183818361423857614238615494565b602002602001015190506000600190505b8281101561429857600085828151811061426557614265615494565b602002602001015190508263ffffffff168163ffffffff161161428e5750600095945050505050565b9150600101614249565b506001949350505050565b600054610100900460ff16806142bc575060005460ff16155b6142d85760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff161580156142fa576000805461ffff19166101011790555b6097805460ff191690558015611490576000805461ff001916905550565b600054610100900460ff1680614331575060005460ff16155b61434d5760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff1615801561436f576000805461ffff19166101011790555b614377614755565b61437f614755565b61438983836147c0565b8015610bb5576000805461ff0019169055505050565b60006143f4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148499092919063ffffffff16565b805190915015610bb557808060200190518101906144129190615e20565b610bb55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b98565b803b6144d55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610b98565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060823b6145755760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b98565b600080846001600160a01b0316846040516145909190615e3d565b600060405180830381855af49150503d80600081146145cb576040519150601f19603f3d011682016040523d82523d6000602084013e6145d0565b606091505b50915091506145f88282604051806060016040528060278152602001615f7360279139614858565b95945050505050565b61460a81614471565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6000818310614650578161275c565b5090919050565b60006001600160a01b0384163b1561474d57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061469b903390899088908890600401615e59565b6020604051808303816000875af19250505080156146d6575060408051601f3d908101601f191682019092526146d391810190615e96565b60015b614733573d808015614704576040519150601f19603f3d011682016040523d82523d6000602084013e614709565b606091505b50805160000361472b5760405162461bcd60e51b8152600401610b9890615dce565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061193b565b50600161193b565b600054610100900460ff168061476e575060005460ff16155b61478a5760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff161580156147ac576000805461ffff19166101011790555b8015611490576000805461ff001916905550565b600054610100900460ff16806147d9575060005460ff16155b6147f55760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff16158015614817576000805461ffff19166101011790555b61012d6148248482615eb3565b5061012e6148328382615eb3565b508015610bb5576000805461ff0019169055505050565b606061193b8484600085614891565b6060831561486757508161275c565b8251156148775782518084602001fd5b8160405162461bcd60e51b8152600401610b989190614b4c565b6060824710156148f25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b98565b843b6149405760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b98565b600080866001600160a01b0316858760405161495c9190615e3d565b60006040518083038185875af1925050503d8060008114614999576040519150601f19603f3d011682016040523d82523d6000602084013e61499e565b606091505b50915091506149ae828286614858565b979650505050505050565b604051806101000160405280600063ffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001614a5160405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff168152602001606081525090565b905290565b6001600160a01b038116811461149057600080fd5b600060208284031215614a7d57600080fd5b813561275c81614a56565b600080600060608486031215614a9d57600080fd5b8335614aa881614a56565b92506020840135614ab881614a56565b929592945050506040919091013590565b6001600160e01b03198116811461149057600080fd5b600060208284031215614af157600080fd5b813561275c81614ac9565b60005b83811015614b17578181015183820152602001614aff565b50506000910152565b60008151808452614b38816020860160208601614afc565b601f01601f19169290920160200192915050565b60208152600061275c6020830184614b20565b60008060408385031215614b7257600080fd5b50508035926020909101359150565b600060208284031215614b9357600080fd5b5035919050565b60008060408385031215614bad57600080fd5b8235614bb881614a56565b946020939093013593505050565b60006040828403121561368357600080fd5b63ffffffff8116811461149057600080fd5b6001600160601b038116811461149057600080fd5b600080600060608486031215614c1457600080fd5b8335614c1f81614bd8565b92506020840135614c2f81614a56565b91506040840135614c3f81614bea565b809150509250925092565b600060208284031215614c5c57600080fd5b813561275c81614bd8565b60008151808452602080850194506020840160005b83811015614c9e57815163ffffffff1687529582019590820190600101614c7c565b509495945050505050565b60208152600061275c6020830184614c67565b60008083601f840112614cce57600080fd5b5081356001600160401b03811115614ce557600080fd5b602083019150836020828501011115614cfd57600080fd5b9250929050565b60008060008060408587031215614d1a57600080fd5b84356001600160401b0380821115614d3157600080fd5b614d3d88838901614cbc565b90965094506020870135915080821115614d5657600080fd5b50614d6387828801614cbc565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715614da757614da7614d6f565b60405290565b604080519081016001600160401b0381118282101715614da757614da7614d6f565b60405161012081016001600160401b0381118282101715614da757614da7614d6f565b604051601f8201601f191681016001600160401b0381118282101715614e1a57614e1a614d6f565b604052919050565b60006001600160401b03821115614e3b57614e3b614d6f565b50601f01601f191660200190565b600082601f830112614e5a57600080fd5b8135614e6d614e6882614e22565b614df2565b818152846020838601011115614e8257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614eb257600080fd5b8235614ebd81614a56565b915060208301356001600160401b03811115614ed857600080fd5b614ee485828601614e49565b9150509250929050565b600060a0828403121561368357600080fd5b60208152815115156020820152600060208301516001600160601b038082166040850152806040860151166060850152505066ffffffffffffff6060840151166080830152608083015160c060a0840152614f5e60e0840182614b20565b905060a0840151601f198483030160c08501526145f88282614b20565b801515811461149057600080fd5b60008060408385031215614f9c57600080fd5b8235614fa781614a56565b91506020830135614fb781614f7b565b809150509250929050565b60008060408385031215614fd557600080fd5b8235614fa781614bd8565b60008060008060808587031215614ff657600080fd5b843561500181614a56565b9350602085013561501181614a56565b92506040850135915060608501356001600160401b0381111561503357600080fd5b61503f87828801614e49565b91505092959194509250565b60008060008060006060868803121561506357600080fd5b853561506e81614bd8565b945060208601356001600160401b038082111561508a57600080fd5b61509689838a01614cbc565b909650945060408801359150808211156150af57600080fd5b506150bc88828901614cbc565b969995985093965092949392505050565b6000806000604084860312156150e257600080fd5b83356150ed81614bd8565b925060208401356001600160401b038082111561510957600080fd5b818601915086601f83011261511d57600080fd5b81358181111561512c57600080fd5b8760208260051b850101111561514157600080fd5b6020830194508093505050509250925092565b6000806040838503121561516757600080fd5b823561517281614a56565b91506020830135614fb781614a56565b6000806000806080858703121561519857600080fd5b84356151a381614a56565b935060208501356151b381614a56565b925060408501356151c381614a56565b915060608501356151d381614a56565b939692955090935050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60006020828403121561522557600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c0657610c0661522c565b805164ffffffffff8116811461526a57600080fd5b919050565b805161526a81614f7b565b600060c0828403121561528c57600080fd5b60405160c081018181106001600160401b03821117156152ae576152ae614d6f565b60405282516152bc81614bea565b815260208301516fffffffffffffffffffffffffffffffff811681146152e157600080fd5b60208201526152f260408401615255565b604082015261530360608401615255565b6060820152608083015161531681614a56565b608082015261532760a0840161526f565b60a08201529392505050565b600181811c9082168061534757607f821691505b60208210810361368357634e487b7160e01b600052602260045260246000fd5b60006001600160401b0382111561538057615380614d6f565b5060051b60200190565b805161526a81614bd8565b600060208083850312156153a857600080fd5b82516001600160401b038111156153be57600080fd5b8301601f810185136153cf57600080fd5b80516153dd614e6882615367565b81815260a091820283018401918482019190888411156153fc57600080fd5b938501935b838510156154755780858a0312156154195760008081fd5b615421614d85565b855161542c81614bd8565b8152858701518782015260408087015161544581614a56565b908201526060868101519082015260808087015161546281614bd8565b9082015283529384019391850191615401565b50979650505050505050565b81810381811115610c0657610c0661522c565b634e487b7160e01b600052603260045260246000fd5b6000813561ffff81168114610c0657600080fd5b6000813560ff81168114610c0657600080fd5b61ffff6154dd836154aa565b1681548161ffff19821617835562ff00006154fa602086016154be565b60101b168262ffffff1983161717835550505050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6001600160601b0382811682821603908082111561555a5761555a61522c565b5092915050565b6001600160601b0381811683821601908082111561555a5761555a61522c565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600063ffffffff8083168181036156835761568361522c565b6001019392505050565b600063ffffffff808916835280881660208401525061ffff861660408301528415156060830152831515608083015260c060a08301526156d060c0830184614c67565b98975050505050505050565b600082601f8301126156ed57600080fd5b815160206156fd614e6883615367565b82815260069290921b8401810191818101908684111561571c57600080fd5b8286015b8481101561576d57604081890312156157395760008081fd5b615741614dad565b815161574c81614bd8565b81528185015161575b81614bd8565b81860152835291830191604001615720565b509695505050505050565b6000602080838503121561578b57600080fd5b82516001600160401b03808211156157a257600080fd5b818501915085601f8301126157b657600080fd5b81516157c4614e6882615367565b81815260059190911b830184019084810190888311156157e357600080fd5b8585015b838110156158b0578051858111156157ff5760008081fd5b8601610120818c03601f19018113156158185760008081fd5b615820614dcf565b8983015181526040808401518b830152606080850151828401526080915081850151818401525060a0808501518284015260c0915081850151818401525060e08085015182840152610100915061587882860161538a565b9083015291830151918883111561588f5760008081fd5b61589d8e8c858701016156dc565b90820152855250509186019186016157e7565b5098975050505050505050565b63ffffffff81811683821601908082111561555a5761555a61522c565b6000600182016158ec576158ec61522c565b5060010190565b601f821115610bb5576000816000526020600020601f850160051c8101602086101561591c5750805b601f850160051c820191505b8181101561135957828155600101615928565b6001600160401b0383111561595257615952614d6f565b615966836159608354615333565b836158f3565b6000601f84116001811461599a57600085156159825750838201355b600019600387901b1c1916600186901b17835561355d565b600083815260209020601f19861690835b828110156159cb57868501358255602094850194600190920191016159ab565b50868210156159e85760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b604081526000615a376040830186886159fa565b82810360208401526149ae8185876159fa565b63ffffffff82811682821603908082111561555a5761555a61522c565b8082028115828204841417610c0657610c0661522c565b600082615a9b57634e487b7160e01b600052601260045260246000fd5b500490565b8135615aab81614bd8565b63ffffffff8116905081548163ffffffff19821617835564ff00000000615ad4602086016154be565b60201b16808364ffffffffff1984161717845566ffff0000000000615afb604087016154aa565b60281b168366ffffffffffffff1984161793508084831717855561ffff60381b615b27606088016154aa565b60381b1661ffff60381b1985168317821717855550505050611e15615b4e608084016154aa565b82546affff000000000000000000191660489190911b6affff00000000000000000016178255565b60008154615b8381615333565b808552602060018381168015615ba05760018114615bba57615be8565b60ff1985168884015283151560051b880183019550615be8565b866000528260002060005b85811015615be05781548a8201860152908301908401615bc5565b890184019650505b505050505092915050565b828152604060208201526000825460ff8116151560408401526001600160601b03808260081c166060850152615c3960808501828460681c166001600160601b03169052565b5060c81c60a083015260c080830152615c59610100830160018501615b76565b828103603f190160e08401526145f88160028601615b76565b600060208284031215615c8457600080fd5b81516001600160401b03811115615c9a57600080fd5b8201601f81018413615cab57600080fd5b8051615cb9614e6882614e22565b818152856020838501011115615cce57600080fd5b6145f8826020830160208601614afc565b600060c0820163ffffffff808b1684526020818b16602086015261ffff8a1660408601528815156060860152871515608086015260c060a08601528286845260e08601905087935060005b87811015615d51578435615d3d81614bd8565b841682529382019390820190600101615d2a565b509c9b505050505050505050505050565b64ffffffffff81811683821601908082111561555a5761555a61522c565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600060208284031215615e3257600080fd5b815161275c81614f7b565b60008251615e4f818460208701614afc565b9190910192915050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e8c90830184614b20565b9695505050505050565b600060208284031215615ea857600080fd5b815161275c81614ac9565b81516001600160401b03811115615ecc57615ecc614d6f565b615ee081615eda8454615333565b846158f3565b602080601f831160018114615f155760008415615efd5750858301515b600019600386901b1c1916600185901b178555611359565b600085815260208120601f198616915b82811015615f4457888601518255948401946001909101908401615f25565b5085821015615f625787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220176aa30f207e9025541dac9c451b5660f7d09f19c40e3df8a2a4ca9332882e4b64736f6c634300081700330000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d000000000000000000000000830bd73e4184cef73443c15111a1df14e495c706

Deployed Bytecode

0x6080604052600436106103765760003560e01c8063704b6c02116101d1578063ac4951f611610102578063cc9df021116100a0578063ed9152c81161006f578063ed9152c814610a68578063f2fde38b14610a9c578063f851a44014610abc578063f8c8765e14610ad157600080fd5b8063cc9df021146109fe578063d0e1a84614610a1e578063d715d10114610a33578063e985e9c514610a4857600080fd5b8063bce7f0da116100dc578063bce7f0da14610994578063becbeb22146109a9578063c37bb58b146109c9578063c87b56dd146109de57600080fd5b8063ac4951f61461091c578063b289a2bb1461093c578063b88d4fde1461097457600080fd5b80638d9763231161016f57806395d89b411161014957806395d89b411461089b578063a22cb465146108b0578063a412bfbb146108d0578063a556ba311461090757600080fd5b80638d976323146108035780638da5cb5b1461081857806392c6d4201461083657600080fd5b806375794a3c116101ab57806375794a3c146107a45780637bf1a627146107b95780637d15f041146107ce5780638456cb59146107ee57600080fd5b8063704b6c021461074f57806370a082311461076f578063715018a61461078f57600080fd5b8063337344a2116102ab5780634818ac421161024957806354b1faeb1161022357806354b1faeb146106d55780635c975abb146106ea5780635f27663b146107025780636352211e1461072f57600080fd5b80634818ac42146106825780634f1ef286146106a25780634fc8d76a146106b557600080fd5b80633f4ba83a116102855780633f4ba83a146106185780633fabc2521461062d57806342842e0e146106425780634364d9731461066257600080fd5b8063337344a2146105975780633659cfe6146105cb5780633b5003c0146105eb57600080fd5b8063095ea7b31161031857806320e47641116102f257806320e476411461051857806323b872dd146105385780632a72731114610558578063303e74df1461058257600080fd5b8063095ea7b31461049657806317cb7292146104b65780631ac8875d146104d657600080fd5b80630553d778116103545780630553d778146103f257806306fdde031461040757806307d7461e14610429578063081812fc1461045e57600080fd5b806301b9a3971461037b57806301e336671461039d57806301ffc9a7146103bd575b600080fd5b34801561038757600080fd5b5061039b610396366004614a6b565b610af1565b005b3480156103a957600080fd5b5061039b6103b8366004614a88565b610b6e565b3480156103c957600080fd5b506103dd6103d8366004614adf565b610bba565b60405190151581526020015b60405180910390f35b3480156103fe57600080fd5b5061039b610c0c565b34801561041357600080fd5b5061041c610e2a565b6040516103e99190614b4c565b34801561043557600080fd5b50610449610444366004614b5f565b610ebd565b604080519283526020830191909152016103e9565b34801561046a57600080fd5b5061047e610479366004614b81565b610fa1565b6040516001600160a01b0390911681526020016103e9565b3480156104a257600080fd5b5061039b6104b1366004614b9a565b611038565b3480156104c257600080fd5b5061039b6104d1366004614bc6565b611148565b3480156104e257600080fd5b5061050a7f9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd70081565b6040519081526020016103e9565b34801561052457600080fd5b5061039b610533366004614bff565b611188565b34801561054457600080fd5b5061039b610553366004614a88565b611361565b34801561056457600080fd5b5061056d611392565b60405163ffffffff90911681526020016103e9565b34801561058e57600080fd5b5061047e6113af565b3480156105a357600080fd5b5061047e7f0000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d81565b3480156105d757600080fd5b5061039b6105e6366004614a6b565b6113cb565b3480156105f757600080fd5b5061060b610606366004614c4a565b611493565b6040516103e99190614ca9565b34801561062457600080fd5b5061039b6117c0565b34801561063957600080fd5b5061050a611817565b34801561064e57600080fd5b5061039b61065d366004614a88565b611834565b34801561066e57600080fd5b5061056d61067d366004614d04565b61184f565b34801561068e57600080fd5b5061039b61069d366004614c4a565b611943565b61039b6106b0366004614e9f565b611d60565b3480156106c157600080fd5b5061039b6106d0366004614eee565b611e19565b3480156106e157600080fd5b5061050a611e59565b3480156106f657600080fd5b5060975460ff166103dd565b34801561070e57600080fd5b5061072261071d366004614c4a565b611e76565b6040516103e99190614f00565b34801561073b57600080fd5b5061047e61074a366004614b81565b61204f565b34801561075b57600080fd5b5061039b61076a366004614a6b565b6120c7565b34801561077b57600080fd5b5061050a61078a366004614a6b565b61211e565b34801561079b57600080fd5b5061039b6121a6565b3480156107b057600080fd5b5061056d6121dc565b3480156107c557600080fd5b5061047e6121f2565b3480156107da57600080fd5b5061039b6107e9366004614a6b565b61220e565b3480156107fa57600080fd5b5061039b612265565b34801561080f57600080fd5b5061039b6122bc565b34801561082457600080fd5b5060c9546001600160a01b031661047e565b34801561084257600080fd5b5061084b612337565b60408051825163ffffffff16815260208084015160ff16908201528282015161ffff908116928201929092526060808401518316908201526080928301519091169181019190915260a0016103e9565b3480156108a757600080fd5b5061041c6123c7565b3480156108bc57600080fd5b5061039b6108cb366004614f89565b6123d7565b3480156108dc57600080fd5b506108e56123e2565b60408051825161ffff16815260209283015160ff1692810192909252016103e9565b34801561091357600080fd5b506103dd612429565b34801561092857600080fd5b5061039b610937366004614fc2565b612444565b34801561094857600080fd5b5061095c610957366004614c4a565b6124e2565b6040516001600160601b0390911681526020016103e9565b34801561098057600080fd5b5061039b61098f366004614fe0565b61252b565b3480156109a057600080fd5b5061039b612563565b3480156109b557600080fd5b5061039b6109c436600461504b565b6125dc565b3480156109d557600080fd5b506103dd6126a3565b3480156109ea57600080fd5b5061041c6109f9366004614b81565b6126bd565b348015610a0a57600080fd5b5061039b610a193660046150cd565b612763565b348015610a2a57600080fd5b5061039b61321d565b348015610a3f57600080fd5b5061050a613330565b348015610a5457600080fd5b506103dd610a63366004615154565b61334e565b348015610a7457600080fd5b5061047e7f000000000000000000000000830bd73e4184cef73443c15111a1df14e495c70681565b348015610aa857600080fd5b5061039b610ab7366004614a6b565b61337d565b348015610ac857600080fd5b5061047e613415565b348015610add57600080fd5b5061039b610aec366004615182565b613431565b6000610afb613564565b60c9549091506001600160a01b0316331480610b23575060048101546001600160a01b031633145b610b4057604051636f0cab8b60e11b815260040160405180910390fd5b81610b49613564565b60060180546001600160a01b0319166001600160a01b03929092169190911790555050565b60c9546001600160a01b03163314610ba15760405162461bcd60e51b8152600401610b98906151de565b60405180910390fd5b610bb56001600160a01b0384168383613588565b505050565b60006001600160e01b031982166380ac58cd60e01b1480610beb57506001600160e01b03198216635b5e139f60e01b145b80610c0657506301ffc9a760e01b6001600160e01b03198316145b92915050565b60c9546001600160a01b03163314610c365760405162461bcd60e51b8152600401610b98906151de565b6000610c40613564565b90506000610cd97f0000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d6001600160a01b031663da35c6646040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc99190615213565b610cd4906001615242565b6135da565b90506000610d717f000000000000000000000000830bd73e4184cef73443c15111a1df14e495c7066001600160a01b0316637d9f6db56040518163ffffffff1660e01b815260040160c060405180830381865afa158015610d3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d62919061527a565b516001600160601b03166135da565b8354600160481b67ffffffffffffffff60501b19909116600160501b63ffffffff86811691820263ffffffff60701b191692909217600160701b9285169283021776ffffffffff0000000000000000ff0000000000000000001916600160901b4264ffffffffff160260ff60481b1916179290921786556040805192835260208301919091529192507fda1b197b06385756fea2566b6b617ea13d1b3d772596d5e7ad6651385ef7acf7910160405180910390a1505050565b606061012d8054610e3a90615333565b80601f0160208091040260200160405190810160405280929190818152602001828054610e6690615333565b8015610eb35780601f10610e8857610100808354040283529160200191610eb3565b820191906000526020600020905b815481529060010190602001808311610e9657829003601f168201915b5050505050905090565b6040516309b8570960e01b8152600481018390526024810182905260016044820152600090819081906001600160a01b037f000000000000000000000000830bd73e4184cef73443c15111a1df14e495c70616906309b8570990606401600060405180830381865afa158015610f37573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f5f9190810190615395565b9050610f6a81613643565b92508060018251610f7b9190615481565b81518110610f8b57610f8b615494565b6020026020010151606001519150509250929050565b600081815261012f60205260408120546001600160a01b031661101b5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b98565b50600090815261013160205260409020546001600160a01b031690565b60006110438261204f565b9050806001600160a01b0316836001600160a01b0316036110b05760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610b98565b336001600160a01b03821614806110cc57506110cc813361334e565b61113e5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b98565b610bb58383613689565b60c9546001600160a01b031633146111725760405162461bcd60e51b8152600401610b98906151de565b8061117b613564565b600201610bb582826154d1565b60975460ff16156111ab5760405162461bcd60e51b8152600401610b9890615510565b60006111b5613564565b63ffffffff85166000818152600583016020526040902091925033906111da9061204f565b6001600160a01b03161461120157604051636a45792360e11b815260040160405180910390fd5b805460ff166112415760405162461bcd60e51b815260206004820152600c60248201526b1b9bdd08185c1c1c9bdd995960a21b6044820152606401610b98565b80546001600160601b03600160681b820481169161126691839161010090041661553a565b6001600160601b0316846001600160601b031611156112ba5760405162461bcd60e51b815260206004820152601060248201526f616d6f756e7420746f6f206c6172676560801b6044820152606401610b98565b6112c48482615561565b82546bffffffffffffffffffffffff60681b1916600160681b6001600160601b03928316021783556040805191861682526001600160a01b038716602083015263ffffffff8816917f1812827f1c6a24a5651bf4de08620620edf7827369871a784625bf0ad118f120910160405180910390a26003830154611359906001600160a01b0316866001600160601b038716613588565b505050505050565b61136b33826136f8565b6113875760405162461bcd60e51b8152600401610b9890615581565b610bb58383836137c8565b600061139c613564565b54600160501b900463ffffffff16919050565b60006113b9613564565b600601546001600160a01b0316919050565b6001600160a01b037f000000000000000000000000aaf173e6b65aa4473c830edb402d26b7a33c5e941630036114135760405162461bcd60e51b8152600401610b98906155d2565b7f000000000000000000000000aaf173e6b65aa4473c830edb402d26b7a33c5e946001600160a01b031661144561396b565b6001600160a01b03161461146b5760405162461bcd60e51b8152600401610b989061561e565b61147481613999565b60408051600080825260208201909252611490918391906139c3565b50565b6060600061149f613564565b905060006114ab6121dc565b63ffffffff1690506000816001600160401b038111156114cd576114cd614d6f565b6040519080825280602002602001820160405280156114f6578160200160208202803683370190505b50905060005b828163ffffffff1610156115485780828263ffffffff168151811061152357611523615494565b63ffffffff909216602092830291909101909101526115418161566a565b90506114fc565b50825460018085015460405163aa0e23c760e01b81526000937f0000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d6001600160a01b03169363aa0e23c7936115c193600160501b90930463ffffffff16928c92600160481b90920461ffff16919081908a9060040161568d565b600060405180830381865afa1580156115de573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116069190810190615778565b90506000836001600160401b0381111561162257611622614d6f565b60405190808252806020026020018201604052801561164b578160200160208202803683370190505b50905060005b82518110156116e15760005b858110156116d85783828151811061167757611677615494565b60200260200101516101000151818151811061169557611695615494565b6020026020010151600001518382815181106116b3576116b3615494565b602002602001018181516116c791906158bd565b63ffffffff1690525060010161165d565b50600101611651565b50600080856001600160401b038111156116fd576116fd614d6f565b604051908082528060200260200182016040528015611726578160200160208202803683370190505b50905060005b868163ffffffff1610156117b1576000848263ffffffff168151811061175457611754615494565b602002602001015163ffffffff1611156117a157808284611774816158da565b95508151811061178657611786615494565b602002602001019063ffffffff16908163ffffffff16815250505b6117aa8161566a565b905061172c565b50908152979650505050505050565b60006117ca613564565b60c9549091506001600160a01b03163314806117f2575060048101546001600160a01b031633145b61180f57604051636f0cab8b60e11b815260040160405180910390fd5b611490613b07565b6000611821613564565b54600160281b900463ffffffff16919050565b610bb58383836040518060200160405280600081525061252b565b600061185d60975460ff1690565b1561187a5760405162461bcd60e51b8152600401610b9890615510565b6000611884613564565b805490915063ffffffff1661189a8160016158bd565b825463ffffffff191663ffffffff9182161783556118bb9033908316613b9a565b63ffffffff811660009081526005830160205260409020600181016118e1888a8361593b565b50600281016118f186888361593b565b508163ffffffff167f65beab8930287623c694d7e645cdd4b7b83bebaaac913f30933d4c691a271e3c8989898960405161192e9493929190615a23565b60405180910390a2509150505b949350505050565b60975460ff16156119665760405162461bcd60e51b8152600401610b9890615510565b60005a90506000611975613564565b8054909150640100000000900460ff166119a2576040516333d63cbd60e01b815260040160405180910390fd5b80546002820154600091600160281b900463ffffffff16906119cd9062010000900460ff1682615242565b8563ffffffff1610156119f35760405163268bc0ad60e01b815260040160405180910390fd5b6119fe8560016158bd565b835463ffffffff91909116600160281b0268ffffffff00000000001990911617835560006001600160a01b037f000000000000000000000000830bd73e4184cef73443c15111a1df14e495c7061663b1296a9483611a5d8960016158bd565b6040516001600160e01b031960e085901b168152600481019290925263ffffffff16602482015260016044820152606401600060405180830381865afa158015611aab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ad39190810190615395565b905060008160018351611ae69190615481565b81518110611af657611af6615494565b602002602001015190508663ffffffff168160600151148015611b2357506001816000015163ffffffff16115b611b40576040516368752cd160e01b815260040160405180910390fd5b60006001611b4c6121dc565b611b569190615a4a565b90506000611b6382613cdf565b905060005b8451811015611be1576000858281518110611b8557611b85615494565b60200260200101519050806080015163ffffffff16600014158015611bba57508363ffffffff16816080015163ffffffff1611155b15611bd8576080810151602082015160019950611bd8918591613dce565b50600101611b68565b50600287015461ffff166000611bf683613ecd565b905060005b818163ffffffff161015611cf6576000611c158583613eec565b905060006127108561ffff168360200151611c309190615a67565b611c3a9190615a7e565b9050611c4581613f36565b825163ffffffff16600090815260058e01602052604090208054600190611c7b90849061010090046001600160601b0316615561565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550816000015163ffffffff167f8a6390ffb12581558b6798514e694cb23b44ff553c82d4e69024ab1fe2230ae282604051611cdb91815260200190565b60405180910390a2505080611cef9061566a565b9050611bfb565b506040805188815263ffffffff8d1660208201527ff48a534da18c3b27deb2da48e4a2d8b1888ad5cb761889d25b692de9da944d22910160405180910390a18715611d53576003890154611d53906001600160a01b03168b613f9e565b5050505050505050505050565b6001600160a01b037f000000000000000000000000aaf173e6b65aa4473c830edb402d26b7a33c5e94163003611da85760405162461bcd60e51b8152600401610b98906155d2565b7f000000000000000000000000aaf173e6b65aa4473c830edb402d26b7a33c5e946001600160a01b0316611dda61396b565b6001600160a01b031614611e005760405162461bcd60e51b8152600401610b989061561e565b611e0982613999565b611e15828260016139c3565b5050565b60c9546001600160a01b03163314611e435760405162461bcd60e51b8152600401610b98906151de565b80611e4c613564565b600101610bb58282615aa0565b6000611e63613564565b54600160701b900463ffffffff16919050565b6040805160c0810182526000808252602082018190529181018290526060808201929092526080810182905260a0810191909152611eb2613564565b63ffffffff831660009081526005919091016020908152604091829020825160c081018452815460ff81161515825261010081046001600160601b0390811694830194909452600160681b810490931693810193909352600160c81b90910466ffffffffffffff166060830152600181018054608084019190611f3490615333565b80601f0160208091040260200160405190810160405280929190818152602001828054611f6090615333565b8015611fad5780601f10611f8257610100808354040283529160200191611fad565b820191906000526020600020905b815481529060010190602001808311611f9057829003601f168201915b50505050508152602001600282018054611fc690615333565b80601f0160208091040260200160405190810160405280929190818152602001828054611ff290615333565b801561203f5780601f106120145761010080835404028352916020019161203f565b820191906000526020600020905b81548152906001019060200180831161202257829003601f168201915b5050505050815250509050919050565b600081815261012f60205260408120546001600160a01b031680610c065760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610b98565b60c9546001600160a01b031633146120f15760405162461bcd60e51b8152600401610b98906151de565b806120fa613564565b60040180546001600160a01b0319166001600160a01b039290921691909117905550565b60006001600160a01b0382166121895760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610b98565b506001600160a01b03166000908152610130602052604090205490565b60c9546001600160a01b031633146121d05760405162461bcd60e51b8152600401610b98906151de565b6121da6000614077565b565b60006121e6613564565b5463ffffffff16919050565b60006121fc613564565b600301546001600160a01b0316919050565b60c9546001600160a01b031633146122385760405162461bcd60e51b8152600401610b98906151de565b80612241613564565b60030180546001600160a01b0319166001600160a01b039290921691909117905550565b600061226f613564565b60c9549091506001600160a01b0316331480612297575060048101546001600160a01b031633145b6122b457604051636f0cab8b60e11b815260040160405180910390fd5b6114906140c9565b60c9546001600160a01b031633146122e65760405162461bcd60e51b8152600401610b98906151de565b60006122f0613564565b80549115156401000000000264ff00000000199092169190911790556040517f2b6b9a9cec683ce4fb9078fe61298719dcfeb0c26e7217bc748101cd3994367590600090a1565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261236a613564565b6040805160a0810182526001929092015463ffffffff8116835260ff640100000000820416602084015261ffff600160281b8204811692840192909252600160381b810482166060840152600160481b9004166080820152919050565b606061012e8054610e3a90615333565b611e15338383614121565b60408051808201909152600080825260208201526123fe613564565b604080518082019091526002919091015461ffff8116825262010000900460ff166020820152919050565b6000612433613564565b54640100000000900460ff16919050565b60c9546001600160a01b0316331461246e5760405162461bcd60e51b8152600401610b98906151de565b6000612478613564565b63ffffffff8416600081815260058301602052604090819020805486151560ff1990911617905551919250907f0f437477476c892b5eab47c4de7c7b038039c74ddde189b97d3315378149d7cb906124d590851515815260200190565b60405180910390a2505050565b6000806124ed613564565b63ffffffff84166000908152600582016020526040902080549192509061193b906001600160601b03600160681b820481169161010090041661553a565b61253533836136f8565b6125515760405162461bcd60e51b8152600401610b9890615581565b61255d848484846141f0565b50505050565b60c9546001600160a01b0316331461258d5760405162461bcd60e51b8152600401610b98906151de565b6000612597613564565b8054911515600160481b0260ff60481b199092169190911790556040517f59a08195999a8f63cd06ccede81a2f98993507dd88f42e1cc630e3df00a1534590600090a1565b60006125e6613564565b9050336125f863ffffffff881661204f565b6001600160a01b03161461261f57604051636a45792360e11b815260040160405180910390fd5b63ffffffff8616600090815260058201602052604090206001810161264586888361593b565b506002810161265584868361593b565b508663ffffffff167f0bee293e8de088ced65538b9072d95ce36471240b1de1e8193ab5e9391294583878787876040516126929493929190615a23565b60405180910390a250505050505050565b60006126ad613564565b54600160481b900460ff16919050565b606060006126c9613564565b600681015463ffffffff85166000908152600583016020526040908190209051635fa2601560e01b81529293506001600160a01b0390911691635fa260159161271791879190600401615bf3565b600060405180830381865afa158015612734573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261275c9190810190615c72565b9392505050565b60975460ff16156127865760405162461bcd60e51b8152600401610b9890615510565b60005a90506000612795613564565b8054909150600160481b900460ff166127c1576040516333d63cbd60e01b815260040160405180910390fd5b6127c96149b9565b60016127d36121dc565b6127dd9190615a4a565b63ffffffff908116825282546040805163368d719960e21b81529051600160501b909204909216916001600160a01b037f0000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d169163da35c664916004808201926020929091908290030181865afa15801561285b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287f9190615213565b8763ffffffff16111580156128a057508063ffffffff168763ffffffff1610155b6128e15760405162461bcd60e51b8152602060048201526012602482015271189859081b185cdd141c9bdc1bdcd85b125960721b6044820152606401610b98565b61291d86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061422392505050565b6129695760405162461bcd60e51b815260206004820152601760248201527f6d75737420626520736f72746564202620756e697175650000000000000000006044820152606401610b98565b60018381015460405163aa0e23c760e01b81526000927f0000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d6001600160a01b03169263aa0e23c7926129d49287928e92600160481b90910461ffff16919081908f908f90600401615cdf565b600060405180830381865afa1580156129f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a199190810190615778565b90506000815111612a6c5760405162461bcd60e51b815260206004820152601e60248201527f6174206c65617374206f6e6520656c696769626c652070726f706f73616c00006044820152606401610b98565b612a778860016158bd565b845463ffffffff91909116600160501b0263ffffffff60501b1990911617845580518190612aa790600190615481565b81518110612ab757612ab7615494565b602090810291909101015160e084018190528454600160701b900463ffffffff1660c0808601829052909101516000918291612af39190610ebd565b9092509050612b038160016158bd565b865463ffffffff91909116600160701b0263ffffffff60701b1990911617865581612b705760405162461bcd60e51b815260206004820152601a60248201527f61756374696f6e526576656e7565206d757374206265203e20300000000000006044820152606401610b98565b600186015461271090612b8e90600160281b900461ffff1684615a67565b612b989190615a7e565b6080860152600186015461271090612bbb90600160381b900461ffff1684615a67565b612bc59190615a7e565b60a086015260005b8351811015612c66576000848281518110612bea57612bea615494565b602002602001015160800151858381518110612c0857612c08615494565b602002602001015160600151868481518110612c2657612c26615494565b602002602001015160400151612c3c9190615242565b612c469190615242565b90508087602001818151612c5a9190615242565b90525050600101612bcd565b506001860154835164010000000090910460ff161115612cfb5760018601548654612ca59163ffffffff1690600160901b900464ffffffffff16615d62565b64ffffffffff168560e0015160c0015111612cfb5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08195b9bdd59da081d1a5b59481c185cdcd95960521b6044820152606401610b98565b60e085015160c00151865464ffffffffff909116600160901b0264ffffffffff60901b1990911617865582516080860151612d369190615a7e565b6040860152602085015160a0860151612d4f9190615a7e565b8560600181815250507fb3719109848cd6df9b4ff39633f0b408e8595e8415ec7bc319800ab3a9dba95d848b8760c0015184868a604001518b60600151604051612dd5979695949392919063ffffffff978816815295909616602086015260408501939093526060840191909152608083015260a082015260c081019190915260e00190565b60405180910390a16000612dec8660000151613cdf565b90506000896001600160401b03811115612e0857612e08614d6f565b604051908082528060200260200182016040528015612e31578160200160208202803683370190505b50905060005b855181101561308d576000868281518110612e5457612e54615494565b602002602001015160e0015190508063ffffffff16600014158015612e895750886000015163ffffffff168163ffffffff1611155b15612ea0576040890151612ea09085908390613dce565b600080888481518110612eb557612eb5615494565b60200260200101516101000151905060005b8e811015612fc2578f8f82818110612ee157612ee1615494565b9050602002016020810190612ef69190614c4a565b93506000828281518110612f0c57612f0c615494565b60200260200101516000015163ffffffff169050868281518110612f3257612f32615494565b602002602001015180612f455750600081115b878381518110612f5757612f57615494565b9115156020928302919091019091015263ffffffff851615801590612f8c57508c6000015163ffffffff168563ffffffff1611155b15612fad57612fad858e6060015183612fa59190615a67565b8a9190613dce565b612fb78185615242565b935050600101612ec7565b50888481518110612fd557612fd5615494565b602002602001015160800151898581518110612ff357612ff3615494565b6020026020010151606001518a868151811061301157613011615494565b6020026020010151604001516130279190615242565b6130319190615242565b821461307f5760405162461bcd60e51b815260206004820152601760248201527f6e6f7420616c6c20766f746573206163636f756e7465640000000000000000006044820152606401610b98565b505050806001019050612e37565b5060005b8151811015613108578181815181106130ac576130ac615494565b60200260200101516131005760405162461bcd60e51b815260206004820152601c60248201527f616c6c20636c69656e744964206d757374206861766520766f746573000000006044820152606401610b98565b600101613091565b50600061311483613ecd565b905060005b818163ffffffff1610156131f55760006131338583613eec565b90506131428160200151613f36565b815163ffffffff16600090815260058d0160205260409020805460019061317890849061010090046001600160601b0316615561565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550806000015163ffffffff167f8a6390ffb12581558b6798514e694cb23b44ff553c82d4e69024ab1fe2230ae282602001516040516131dc91815260200190565b60405180910390a2506131ee8161566a565b9050613119565b50600389015461320e906001600160a01b03168b613f9e565b50505050505050505050505050565b60c9546001600160a01b031633146132475760405162461bcd60e51b8152600401610b98906151de565b6000613251613564565b905060006132b67f000000000000000000000000830bd73e4184cef73443c15111a1df14e495c7066001600160a01b0316637d9f6db56040518163ffffffff1660e01b815260040160c060405180830381865afa158015610d3e573d6000803e3d6000fd5b825464ff000000001963ffffffff8316600160281b021668ffffffffff0000000019909116176401000000001783556040519091507f8157ff66129c00501479a49058e6c0b2f966c1e797fbb240812faa57ad5b68679061332490839063ffffffff91909116815260200190565b60405180910390a15050565b600061333a613564565b54600160901b900464ffffffffff16919050565b6001600160a01b0391821660009081526101326020908152604080832093909416825291909152205460ff1690565b60c9546001600160a01b031633146133a75760405162461bcd60e51b8152600401610b98906151de565b6001600160a01b03811661340c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b98565b61149081614077565b600061341f613564565b600401546001600160a01b0316919050565b600054610100900460ff168061344a575060005460ff16155b6134665760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff16158015613488576000805461ffff19166101011790555b6134906142a3565b6134e7604051806040016040528060128152602001712737bab7399021b634b2b73a102a37b5b2b760711b8152506040518060400160405280600b81526020016a1393d55394d0d31251539560aa1b815250614318565b60006134f1613564565b805463ffffffff19166001178155905061350a86614077565b6004810180546001600160a01b038088166001600160a01b0319928316179092556003830180548784169083161790556006909201805491851691909216179055801561355d576000805461ff00191690555b5050505050565b7f9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd70090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610bb590849061439f565b600063ffffffff82111561363f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610b98565b5090565b6000805b82518110156136835782818151811061366257613662615494565b602002602001015160200151826136799190615242565b9150600101613647565b50919050565b60008181526101316020526040902080546001600160a01b0319166001600160a01b03841690811790915581906136bf8261204f565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600081815261012f60205260408120546001600160a01b03166137725760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b98565b600061377d8361204f565b9050806001600160a01b0316846001600160a01b031614806137b85750836001600160a01b03166137ad84610fa1565b6001600160a01b0316145b8061193b575061193b818561334e565b826001600160a01b03166137db8261204f565b6001600160a01b0316146138435760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610b98565b6001600160a01b0382166138a55760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610b98565b6138b0600082613689565b6001600160a01b0383166000908152610130602052604081208054600192906138da908490615481565b90915550506001600160a01b038216600090815261013060205260408120805460019290613909908490615242565b9091555050600081815261012f602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60c9546001600160a01b031633146114905760405162461bcd60e51b8152600401610b98906151de565b60006139cd61396b565b90506139d884614471565b6000835111806139e55750815b156139f6576139f48484614516565b505b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143805460ff1661355d57805460ff191660011781556040516001600160a01b0383166024820152613a7590869060440160408051601f198184030181529190526020810180516001600160e01b0316631b2ce7f360e11b179052614516565b50805460ff19168155613a8661396b565b6001600160a01b0316826001600160a01b031614613afe5760405162461bcd60e51b815260206004820152602f60248201527f45524331393637557067726164653a207570677261646520627265616b73206660448201526e75727468657220757067726164657360881b6064820152608401610b98565b61355d85614601565b60975460ff16613b505760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610b98565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216613bf05760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b98565b600081815261012f60205260409020546001600160a01b031615613c565760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b98565b6001600160a01b038216600090815261013060205260408120805460019290613c80908490615242565b9091555050600081815261012f602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60408051606080820183528082526020820152600091810191909152613d068260016158bd565b63ffffffff166001600160401b03811115613d2357613d23614d6f565b604051908082528060200260200182016040528015613d4c578160200160208202803683370190505b508152613d5a8260026158bd565b63ffffffff166001600160401b03811115613d7757613d77614d6f565b604051908082528060200260200182016040528015613dbc57816020015b6040805180820190915260008082526020820152815260200190600190039081613d955790505b50602082015260016040820152919050565b600083600001518363ffffffff1681518110613dec57613dec615494565b602002602001015190508063ffffffff16600003613e8f5760408401805190613e148261566a565b63ffffffff1663ffffffff1681525090508084600001518463ffffffff1681518110613e4257613e42615494565b602002602001019063ffffffff16908163ffffffff16815250508284602001518263ffffffff1681518110613e7957613e79615494565b602090810291909101015163ffffffff90911690525b8184602001518263ffffffff1681518110613eac57613eac615494565b6020026020010151602001818151613ec49190615242565b90525050505050565b600060018260400151613ee09190615a4a565b63ffffffff1692915050565b60408051808201909152600080825260208201526020830151613f108360016158bd565b63ffffffff1681518110613f2657613f26615494565b6020026020010151905092915050565b60006001600160601b0382111561363f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b6064820152608401610b98565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015613fe5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140099190615213565b90508060000361401857505050565b600061402948642e90edd000614641565b9050600061403d3a63773594008401614641565b90506000618ca05a8603019050600061405882840286614641565b905061406e6001600160a01b0388163283613588565b50505050505050565b60c980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60975460ff16156140ec5760405162461bcd60e51b8152600401610b9890615510565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613b7d3390565b816001600160a01b0316836001600160a01b0316036141825760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b98565b6001600160a01b0383811660008181526101326020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6141fb8484846137c8565b61420784848484614657565b61255d5760405162461bcd60e51b8152600401610b9890615dce565b80516000908183818361423857614238615494565b602002602001015190506000600190505b8281101561429857600085828151811061426557614265615494565b602002602001015190508263ffffffff168163ffffffff161161428e5750600095945050505050565b9150600101614249565b506001949350505050565b600054610100900460ff16806142bc575060005460ff16155b6142d85760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff161580156142fa576000805461ffff19166101011790555b6097805460ff191690558015611490576000805461ff001916905550565b600054610100900460ff1680614331575060005460ff16155b61434d5760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff1615801561436f576000805461ffff19166101011790555b614377614755565b61437f614755565b61438983836147c0565b8015610bb5576000805461ff0019169055505050565b60006143f4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148499092919063ffffffff16565b805190915015610bb557808060200190518101906144129190615e20565b610bb55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b98565b803b6144d55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610b98565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060823b6145755760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b98565b600080846001600160a01b0316846040516145909190615e3d565b600060405180830381855af49150503d80600081146145cb576040519150601f19603f3d011682016040523d82523d6000602084013e6145d0565b606091505b50915091506145f88282604051806060016040528060278152602001615f7360279139614858565b95945050505050565b61460a81614471565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6000818310614650578161275c565b5090919050565b60006001600160a01b0384163b1561474d57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061469b903390899088908890600401615e59565b6020604051808303816000875af19250505080156146d6575060408051601f3d908101601f191682019092526146d391810190615e96565b60015b614733573d808015614704576040519150601f19603f3d011682016040523d82523d6000602084013e614709565b606091505b50805160000361472b5760405162461bcd60e51b8152600401610b9890615dce565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061193b565b50600161193b565b600054610100900460ff168061476e575060005460ff16155b61478a5760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff161580156147ac576000805461ffff19166101011790555b8015611490576000805461ff001916905550565b600054610100900460ff16806147d9575060005460ff16155b6147f55760405162461bcd60e51b8152600401610b9890615d80565b600054610100900460ff16158015614817576000805461ffff19166101011790555b61012d6148248482615eb3565b5061012e6148328382615eb3565b508015610bb5576000805461ff0019169055505050565b606061193b8484600085614891565b6060831561486757508161275c565b8251156148775782518084602001fd5b8160405162461bcd60e51b8152600401610b989190614b4c565b6060824710156148f25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b98565b843b6149405760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b98565b600080866001600160a01b0316858760405161495c9190615e3d565b60006040518083038185875af1925050503d8060008114614999576040519150601f19603f3d011682016040523d82523d6000602084013e61499e565b606091505b50915091506149ae828286614858565b979650505050505050565b604051806101000160405280600063ffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001614a5160405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff168152602001606081525090565b905290565b6001600160a01b038116811461149057600080fd5b600060208284031215614a7d57600080fd5b813561275c81614a56565b600080600060608486031215614a9d57600080fd5b8335614aa881614a56565b92506020840135614ab881614a56565b929592945050506040919091013590565b6001600160e01b03198116811461149057600080fd5b600060208284031215614af157600080fd5b813561275c81614ac9565b60005b83811015614b17578181015183820152602001614aff565b50506000910152565b60008151808452614b38816020860160208601614afc565b601f01601f19169290920160200192915050565b60208152600061275c6020830184614b20565b60008060408385031215614b7257600080fd5b50508035926020909101359150565b600060208284031215614b9357600080fd5b5035919050565b60008060408385031215614bad57600080fd5b8235614bb881614a56565b946020939093013593505050565b60006040828403121561368357600080fd5b63ffffffff8116811461149057600080fd5b6001600160601b038116811461149057600080fd5b600080600060608486031215614c1457600080fd5b8335614c1f81614bd8565b92506020840135614c2f81614a56565b91506040840135614c3f81614bea565b809150509250925092565b600060208284031215614c5c57600080fd5b813561275c81614bd8565b60008151808452602080850194506020840160005b83811015614c9e57815163ffffffff1687529582019590820190600101614c7c565b509495945050505050565b60208152600061275c6020830184614c67565b60008083601f840112614cce57600080fd5b5081356001600160401b03811115614ce557600080fd5b602083019150836020828501011115614cfd57600080fd5b9250929050565b60008060008060408587031215614d1a57600080fd5b84356001600160401b0380821115614d3157600080fd5b614d3d88838901614cbc565b90965094506020870135915080821115614d5657600080fd5b50614d6387828801614cbc565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715614da757614da7614d6f565b60405290565b604080519081016001600160401b0381118282101715614da757614da7614d6f565b60405161012081016001600160401b0381118282101715614da757614da7614d6f565b604051601f8201601f191681016001600160401b0381118282101715614e1a57614e1a614d6f565b604052919050565b60006001600160401b03821115614e3b57614e3b614d6f565b50601f01601f191660200190565b600082601f830112614e5a57600080fd5b8135614e6d614e6882614e22565b614df2565b818152846020838601011115614e8257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614eb257600080fd5b8235614ebd81614a56565b915060208301356001600160401b03811115614ed857600080fd5b614ee485828601614e49565b9150509250929050565b600060a0828403121561368357600080fd5b60208152815115156020820152600060208301516001600160601b038082166040850152806040860151166060850152505066ffffffffffffff6060840151166080830152608083015160c060a0840152614f5e60e0840182614b20565b905060a0840151601f198483030160c08501526145f88282614b20565b801515811461149057600080fd5b60008060408385031215614f9c57600080fd5b8235614fa781614a56565b91506020830135614fb781614f7b565b809150509250929050565b60008060408385031215614fd557600080fd5b8235614fa781614bd8565b60008060008060808587031215614ff657600080fd5b843561500181614a56565b9350602085013561501181614a56565b92506040850135915060608501356001600160401b0381111561503357600080fd5b61503f87828801614e49565b91505092959194509250565b60008060008060006060868803121561506357600080fd5b853561506e81614bd8565b945060208601356001600160401b038082111561508a57600080fd5b61509689838a01614cbc565b909650945060408801359150808211156150af57600080fd5b506150bc88828901614cbc565b969995985093965092949392505050565b6000806000604084860312156150e257600080fd5b83356150ed81614bd8565b925060208401356001600160401b038082111561510957600080fd5b818601915086601f83011261511d57600080fd5b81358181111561512c57600080fd5b8760208260051b850101111561514157600080fd5b6020830194508093505050509250925092565b6000806040838503121561516757600080fd5b823561517281614a56565b91506020830135614fb781614a56565b6000806000806080858703121561519857600080fd5b84356151a381614a56565b935060208501356151b381614a56565b925060408501356151c381614a56565b915060608501356151d381614a56565b939692955090935050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60006020828403121561522557600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c0657610c0661522c565b805164ffffffffff8116811461526a57600080fd5b919050565b805161526a81614f7b565b600060c0828403121561528c57600080fd5b60405160c081018181106001600160401b03821117156152ae576152ae614d6f565b60405282516152bc81614bea565b815260208301516fffffffffffffffffffffffffffffffff811681146152e157600080fd5b60208201526152f260408401615255565b604082015261530360608401615255565b6060820152608083015161531681614a56565b608082015261532760a0840161526f565b60a08201529392505050565b600181811c9082168061534757607f821691505b60208210810361368357634e487b7160e01b600052602260045260246000fd5b60006001600160401b0382111561538057615380614d6f565b5060051b60200190565b805161526a81614bd8565b600060208083850312156153a857600080fd5b82516001600160401b038111156153be57600080fd5b8301601f810185136153cf57600080fd5b80516153dd614e6882615367565b81815260a091820283018401918482019190888411156153fc57600080fd5b938501935b838510156154755780858a0312156154195760008081fd5b615421614d85565b855161542c81614bd8565b8152858701518782015260408087015161544581614a56565b908201526060868101519082015260808087015161546281614bd8565b9082015283529384019391850191615401565b50979650505050505050565b81810381811115610c0657610c0661522c565b634e487b7160e01b600052603260045260246000fd5b6000813561ffff81168114610c0657600080fd5b6000813560ff81168114610c0657600080fd5b61ffff6154dd836154aa565b1681548161ffff19821617835562ff00006154fa602086016154be565b60101b168262ffffff1983161717835550505050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6001600160601b0382811682821603908082111561555a5761555a61522c565b5092915050565b6001600160601b0381811683821601908082111561555a5761555a61522c565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600063ffffffff8083168181036156835761568361522c565b6001019392505050565b600063ffffffff808916835280881660208401525061ffff861660408301528415156060830152831515608083015260c060a08301526156d060c0830184614c67565b98975050505050505050565b600082601f8301126156ed57600080fd5b815160206156fd614e6883615367565b82815260069290921b8401810191818101908684111561571c57600080fd5b8286015b8481101561576d57604081890312156157395760008081fd5b615741614dad565b815161574c81614bd8565b81528185015161575b81614bd8565b81860152835291830191604001615720565b509695505050505050565b6000602080838503121561578b57600080fd5b82516001600160401b03808211156157a257600080fd5b818501915085601f8301126157b657600080fd5b81516157c4614e6882615367565b81815260059190911b830184019084810190888311156157e357600080fd5b8585015b838110156158b0578051858111156157ff5760008081fd5b8601610120818c03601f19018113156158185760008081fd5b615820614dcf565b8983015181526040808401518b830152606080850151828401526080915081850151818401525060a0808501518284015260c0915081850151818401525060e08085015182840152610100915061587882860161538a565b9083015291830151918883111561588f5760008081fd5b61589d8e8c858701016156dc565b90820152855250509186019186016157e7565b5098975050505050505050565b63ffffffff81811683821601908082111561555a5761555a61522c565b6000600182016158ec576158ec61522c565b5060010190565b601f821115610bb5576000816000526020600020601f850160051c8101602086101561591c5750805b601f850160051c820191505b8181101561135957828155600101615928565b6001600160401b0383111561595257615952614d6f565b615966836159608354615333565b836158f3565b6000601f84116001811461599a57600085156159825750838201355b600019600387901b1c1916600186901b17835561355d565b600083815260209020601f19861690835b828110156159cb57868501358255602094850194600190920191016159ab565b50868210156159e85760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b604081526000615a376040830186886159fa565b82810360208401526149ae8185876159fa565b63ffffffff82811682821603908082111561555a5761555a61522c565b8082028115828204841417610c0657610c0661522c565b600082615a9b57634e487b7160e01b600052601260045260246000fd5b500490565b8135615aab81614bd8565b63ffffffff8116905081548163ffffffff19821617835564ff00000000615ad4602086016154be565b60201b16808364ffffffffff1984161717845566ffff0000000000615afb604087016154aa565b60281b168366ffffffffffffff1984161793508084831717855561ffff60381b615b27606088016154aa565b60381b1661ffff60381b1985168317821717855550505050611e15615b4e608084016154aa565b82546affff000000000000000000191660489190911b6affff00000000000000000016178255565b60008154615b8381615333565b808552602060018381168015615ba05760018114615bba57615be8565b60ff1985168884015283151560051b880183019550615be8565b866000528260002060005b85811015615be05781548a8201860152908301908401615bc5565b890184019650505b505050505092915050565b828152604060208201526000825460ff8116151560408401526001600160601b03808260081c166060850152615c3960808501828460681c166001600160601b03169052565b5060c81c60a083015260c080830152615c59610100830160018501615b76565b828103603f190160e08401526145f88160028601615b76565b600060208284031215615c8457600080fd5b81516001600160401b03811115615c9a57600080fd5b8201601f81018413615cab57600080fd5b8051615cb9614e6882614e22565b818152856020838501011115615cce57600080fd5b6145f8826020830160208601614afc565b600060c0820163ffffffff808b1684526020818b16602086015261ffff8a1660408601528815156060860152871515608086015260c060a08601528286845260e08601905087935060005b87811015615d51578435615d3d81614bd8565b841682529382019390820190600101615d2a565b509c9b505050505050505050505050565b64ffffffffff81811683821601908082111561555a5761555a61522c565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600060208284031215615e3257600080fd5b815161275c81614f7b565b60008251615e4f818460208701614afc565b9190910192915050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e8c90830184614b20565b9695505050505050565b600060208284031215615ea857600080fd5b815161275c81614ac9565b81516001600160401b03811115615ecc57615ecc614d6f565b615ee081615eda8454615333565b846158f3565b602080601f831160018114615f155760008415615efd5750858301515b600019600386901b1c1916600185901b178555611359565b600085815260208120601f198616915b82811015615f4457888601518255948401946001909101908401615f25565b5085821015615f625787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220176aa30f207e9025541dac9c451b5660f7d09f19c40e3df8a2a4ca9332882e4b64736f6c63430008170033

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

0000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d000000000000000000000000830bd73e4184cef73443c15111a1df14e495c706

-----Decoded View---------------
Arg [0] : nounsDAO_ (address): 0x6f3E6272A167e8AcCb32072d08E0957F9c79223d
Arg [1] : auctionHouse_ (address): 0x830BD73E4184ceF73443C15111a1DF14e495C706

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000006f3e6272a167e8accb32072d08e0957f9c79223d
Arg [1] : 000000000000000000000000830bd73e4184cef73443c15111a1df14e495c706


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
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.