Goerli Testnet

Contract

0x6763C3210bdC1D9A1f917706a16F259913198376
Source Code

Overview

ETH Balance

0 ETH

Multi Chain

Multichain Addresses

N/A
Transaction Hash
Method
Block
From
To
Value
0x6102006084860462023-02-13 18:09:36300 days 17 hrs ago1676311776IN
 Create: Governor
0 ETH0.1008358420.87659856

Latest 25 internal transactions (View All)

Advanced mode:
Parent Txn Hash Block From To Value
101872582023-12-10 2:10:361 day 9 hrs ago1702174236
0x6763C3...13198376
0 ETH
101872512023-12-10 2:08:361 day 9 hrs ago1702174116
0x6763C3...13198376
0 ETH
101872452023-12-10 2:06:361 day 9 hrs ago1702173996
0x6763C3...13198376
0 ETH
101847432023-12-09 15:23:001 day 20 hrs ago1702135380
0x6763C3...13198376
0 ETH
101581612023-12-04 20:54:006 days 14 hrs ago1701723240
0x6763C3...13198376
0 ETH
101410392023-12-01 22:01:369 days 13 hrs ago1701468096
0x6763C3...13198376
0 ETH
101410272023-12-01 21:58:489 days 13 hrs ago1701467928
0x6763C3...13198376
0 ETH
101409832023-12-01 21:48:369 days 13 hrs ago1701467316
0x6763C3...13198376
0 ETH
101409602023-12-01 21:42:009 days 13 hrs ago1701466920
0x6763C3...13198376
0 ETH
101408442023-12-01 21:14:369 days 14 hrs ago1701465276
0x6763C3...13198376
0 ETH
101408122023-12-01 21:06:369 days 14 hrs ago1701464796
0x6763C3...13198376
0 ETH
101407552023-12-01 20:51:369 days 14 hrs ago1701463896
0x6763C3...13198376
0 ETH
101407352023-12-01 20:45:249 days 14 hrs ago1701463524
0x6763C3...13198376
0 ETH
101403922023-12-01 19:16:369 days 16 hrs ago1701458196
0x6763C3...13198376
0 ETH
101403822023-12-01 19:14:369 days 16 hrs ago1701458076
0x6763C3...13198376
0 ETH
101403092023-12-01 18:57:249 days 16 hrs ago1701457044
0x6763C3...13198376
0 ETH
101402782023-12-01 18:49:489 days 16 hrs ago1701456588
0x6763C3...13198376
0 ETH
101272572023-11-29 12:19:1211 days 23 hrs ago1701260352
0x6763C3...13198376
0 ETH
101227202023-11-28 16:52:2412 days 18 hrs ago1701190344
0x6763C3...13198376
0 ETH
101178672023-11-27 20:18:3613 days 15 hrs ago1701116316
0x6763C3...13198376
0 ETH
101177482023-11-27 19:49:0013 days 15 hrs ago1701114540
0x6763C3...13198376
0 ETH
101177242023-11-27 19:42:4813 days 15 hrs ago1701114168
0x6763C3...13198376
0 ETH
101154472023-11-27 9:56:0014 days 1 hr ago1701078960
0x6763C3...13198376
0 ETH
101134192023-11-27 1:06:3614 days 10 hrs ago1701047196
0x6763C3...13198376
0 ETH
101133882023-11-27 0:56:3614 days 10 hrs ago1701046596
0x6763C3...13198376
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Governor

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 500000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

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

import { UUPS } from "../../lib/proxy/UUPS.sol";
import { Ownable } from "../../lib/utils/Ownable.sol";
import { EIP712 } from "../../lib/utils/EIP712.sol";
import { SafeCast } from "../../lib/utils/SafeCast.sol";

import { GovernorStorageV1 } from "./storage/GovernorStorageV1.sol";
import { Token } from "../../token/Token.sol";
import { Treasury } from "../treasury/Treasury.sol";
import { IManager } from "../../manager/IManager.sol";
import { IGovernor } from "./IGovernor.sol";
import { ProposalHasher } from "./ProposalHasher.sol";
import { VersionedContract } from "../../VersionedContract.sol";

/// @title Governor
/// @author Rohan Kulkarni
/// @notice A DAO's proposal manager and transaction scheduler
/// @custom:repo github.com/ourzora/nouns-protocol
/// Modified from:
/// - OpenZeppelin Contracts v4.7.3 (governance/extensions/GovernorTimelockControl.sol)
/// - NounsDAOLogicV1.sol commit 2cbe6c7 - licensed under the BSD-3-Clause license.
contract Governor is IGovernor, VersionedContract, UUPS, Ownable, EIP712, ProposalHasher, GovernorStorageV1 {
    ///                                                          ///
    ///                         IMMUTABLES                       ///
    ///                                                          ///

    /// @notice The EIP-712 typehash to vote with a signature
    bytes32 public immutable VOTE_TYPEHASH = keccak256("Vote(address voter,uint256 proposalId,uint256 support,uint256 nonce,uint256 deadline)");

    /// @notice The minimum proposal threshold bps setting
    uint256 public immutable MIN_PROPOSAL_THRESHOLD_BPS = 1;

    /// @notice The maximum proposal threshold bps setting
    uint256 public immutable MAX_PROPOSAL_THRESHOLD_BPS = 1000;

    /// @notice The minimum quorum threshold bps setting
    uint256 public immutable MIN_QUORUM_THRESHOLD_BPS = 200;

    /// @notice The maximum quorum threshold bps setting
    uint256 public immutable MAX_QUORUM_THRESHOLD_BPS = 2000;

    /// @notice The minimum voting delay setting
    uint256 public immutable MIN_VOTING_DELAY = 1 seconds;

    /// @notice The maximum voting delay setting
    uint256 public immutable MAX_VOTING_DELAY = 24 weeks;

    /// @notice The minimum voting period setting
    uint256 public immutable MIN_VOTING_PERIOD = 10 minutes;

    /// @notice The maximum voting period setting
    uint256 public immutable MAX_VOTING_PERIOD = 24 weeks;

    /// @notice The basis points for 100%
    uint256 private immutable BPS_PER_100_PERCENT = 10_000;

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

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

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

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

    /// @notice Initializes a DAO's governor
    /// @param _treasury The DAO's treasury address
    /// @param _token The DAO's governance token address
    /// @param _vetoer The address eligible to veto proposals
    /// @param _votingDelay The voting delay
    /// @param _votingPeriod The voting period
    /// @param _proposalThresholdBps The proposal threshold basis points
    /// @param _quorumThresholdBps The quorum threshold basis points
    function initialize(
        address _treasury,
        address _token,
        address _vetoer,
        uint256 _votingDelay,
        uint256 _votingPeriod,
        uint256 _proposalThresholdBps,
        uint256 _quorumThresholdBps
    ) external initializer {
        // Ensure the caller is the contract manager
        if (msg.sender != address(manager)) revert ONLY_MANAGER();

        // Ensure non-zero addresses are provided
        if (_treasury == address(0)) revert ADDRESS_ZERO();
        if (_token == address(0)) revert ADDRESS_ZERO();

        // If a vetoer is specified, store its address
        if (_vetoer != address(0)) settings.vetoer = _vetoer;

        // Ensure the specified governance settings are valid
        if (_proposalThresholdBps < MIN_PROPOSAL_THRESHOLD_BPS || _proposalThresholdBps > MAX_PROPOSAL_THRESHOLD_BPS)
            revert INVALID_PROPOSAL_THRESHOLD_BPS();
        if (_quorumThresholdBps < MIN_QUORUM_THRESHOLD_BPS || _quorumThresholdBps > MAX_QUORUM_THRESHOLD_BPS) revert INVALID_QUORUM_THRESHOLD_BPS();
        if (_proposalThresholdBps >= _quorumThresholdBps) revert INVALID_PROPOSAL_THRESHOLD_BPS();
        if (_votingDelay < MIN_VOTING_DELAY || _votingDelay > MAX_VOTING_DELAY) revert INVALID_VOTING_DELAY();
        if (_votingPeriod < MIN_VOTING_PERIOD || _votingPeriod > MAX_VOTING_PERIOD) revert INVALID_VOTING_PERIOD();

        // Store the governor settings
        settings.treasury = Treasury(payable(_treasury));
        settings.token = Token(_token);
        settings.votingDelay = SafeCast.toUint48(_votingDelay);
        settings.votingPeriod = SafeCast.toUint48(_votingPeriod);
        settings.proposalThresholdBps = SafeCast.toUint16(_proposalThresholdBps);
        settings.quorumThresholdBps = SafeCast.toUint16(_quorumThresholdBps);

        // Initialize EIP-712 support
        __EIP712_init(string.concat(settings.token.symbol(), " GOV"), "1");

        // Grant ownership to the treasury
        __Ownable_init(_treasury);
    }

    ///                                                          ///
    ///                        CREATE PROPOSAL                   ///
    ///                                                          ///

    /// @notice Creates a proposal
    /// @param _targets The target addresses to call
    /// @param _values The ETH values of each call
    /// @param _calldatas The calldata of each call
    /// @param _description The proposal description
    function propose(
        address[] memory _targets,
        uint256[] memory _values,
        bytes[] memory _calldatas,
        string memory _description
    ) external returns (bytes32) {
        // Get the current proposal threshold
        uint256 currentProposalThreshold = proposalThreshold();

        // Cannot realistically underflow and `getVotes` would revert
        unchecked {
            // Ensure the caller's voting weight is greater than or equal to the threshold
            if (getVotes(msg.sender, block.timestamp - 1) <= proposalThreshold()) {
                revert BELOW_PROPOSAL_THRESHOLD();
            }
        }

        // Cache the number of targets
        uint256 numTargets = _targets.length;

        // Ensure at least one target exists
        if (numTargets == 0) revert PROPOSAL_TARGET_MISSING();

        // Ensure the number of targets matches the number of values and calldata
        if (numTargets != _values.length) revert PROPOSAL_LENGTH_MISMATCH();
        if (numTargets != _calldatas.length) revert PROPOSAL_LENGTH_MISMATCH();

        // Compute the description hash
        bytes32 descriptionHash = keccak256(bytes(_description));

        // Compute the proposal id
        bytes32 proposalId = hashProposal(_targets, _values, _calldatas, descriptionHash, msg.sender);

        // Get the pointer to store the proposal
        Proposal storage proposal = proposals[proposalId];

        // Ensure the proposal doesn't already exist
        if (proposal.voteStart != 0) revert PROPOSAL_EXISTS(proposalId);

        // Used to store the snapshot and deadline
        uint256 snapshot;
        uint256 deadline;

        // Cannot realistically overflow
        unchecked {
            // Compute the snapshot and deadline
            snapshot = block.timestamp + settings.votingDelay;
            deadline = snapshot + settings.votingPeriod;
        }

        // Store the proposal data
        proposal.voteStart = SafeCast.toUint32(snapshot);
        proposal.voteEnd = SafeCast.toUint32(deadline);
        proposal.proposalThreshold = SafeCast.toUint32(currentProposalThreshold);
        proposal.quorumVotes = SafeCast.toUint32(quorum());
        proposal.proposer = msg.sender;
        proposal.timeCreated = SafeCast.toUint32(block.timestamp);

        emit ProposalCreated(proposalId, _targets, _values, _calldatas, _description, descriptionHash, proposal);

        return proposalId;
    }

    ///                                                          ///
    ///                          CAST VOTE                       ///
    ///                                                          ///

    /// @notice Casts a vote
    /// @param _proposalId The proposal id
    /// @param _support The support value (0 = Against, 1 = For, 2 = Abstain)
    function castVote(bytes32 _proposalId, uint256 _support) external returns (uint256) {
        return _castVote(_proposalId, msg.sender, _support, "");
    }

    /// @notice Casts a vote with a reason
    /// @param _proposalId The proposal id
    /// @param _support The support value (0 = Against, 1 = For, 2 = Abstain)
    /// @param _reason The vote reason
    function castVoteWithReason(
        bytes32 _proposalId,
        uint256 _support,
        string memory _reason
    ) external returns (uint256) {
        return _castVote(_proposalId, msg.sender, _support, _reason);
    }

    /// @notice Casts a signed vote
    /// @param _voter The voter address
    /// @param _proposalId The proposal id
    /// @param _support The support value (0 = Against, 1 = For, 2 = Abstain)
    /// @param _deadline The signature deadline
    /// @param _v The 129th byte and chain id of the signature
    /// @param _r The first 64 bytes of the signature
    /// @param _s Bytes 64-128 of the signature
    function castVoteBySig(
        address _voter,
        bytes32 _proposalId,
        uint256 _support,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external returns (uint256) {
        // Ensure the deadline has not passed
        if (block.timestamp > _deadline) revert EXPIRED_SIGNATURE();

        // Used to store the signed digest
        bytes32 digest;

        // Cannot realistically overflow
        unchecked {
            // Compute the message
            digest = keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR(),
                    keccak256(abi.encode(VOTE_TYPEHASH, _voter, _proposalId, _support, nonces[_voter]++, _deadline))
                )
            );
        }

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

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

        return _castVote(_proposalId, _voter, _support, "");
    }

    /// @dev Stores a vote
    /// @param _proposalId The proposal id
    /// @param _voter The voter address
    /// @param _support The vote choice
    function _castVote(
        bytes32 _proposalId,
        address _voter,
        uint256 _support,
        string memory _reason
    ) internal returns (uint256) {
        // Ensure voting is active
        if (state(_proposalId) != ProposalState.Active) revert VOTING_NOT_STARTED();

        // Ensure the voter hasn't already voted
        if (hasVoted[_proposalId][_voter]) revert ALREADY_VOTED();

        // Ensure the vote is valid
        if (_support > 2) revert INVALID_VOTE();

        // Record the voter as having voted
        hasVoted[_proposalId][_voter] = true;

        // Get the pointer to the proposal
        Proposal storage proposal = proposals[_proposalId];

        // Used to store the voter's weight
        uint256 weight;

        // Cannot realistically underflow and `getVotes` would revert
        unchecked {
            // Get the voter's weight at the time the proposal was created
            weight = getVotes(_voter, proposal.timeCreated);

            // If the vote is against:
            if (_support == 0) {
                // Update the total number of votes against
                proposal.againstVotes += SafeCast.toUint32(weight);

                // Else if the vote is for:
            } else if (_support == 1) {
                // Update the total number of votes for
                proposal.forVotes += SafeCast.toUint32(weight);

                // Else if the vote is to abstain:
            } else if (_support == 2) {
                // Update the total number of votes abstaining
                proposal.abstainVotes += SafeCast.toUint32(weight);
            }
        }

        emit VoteCast(_voter, _proposalId, _support, weight, _reason);

        return weight;
    }

    ///                                                          ///
    ///                        QUEUE PROPOSAL                    ///
    ///                                                          ///

    /// @notice Queues a proposal
    /// @param _proposalId The proposal id
    function queue(bytes32 _proposalId) external returns (uint256 eta) {
        // Ensure the proposal has succeeded
        if (state(_proposalId) != ProposalState.Succeeded) revert PROPOSAL_UNSUCCESSFUL();

        // Schedule the proposal for execution
        eta = settings.treasury.queue(_proposalId);

        emit ProposalQueued(_proposalId, eta);
    }

    ///                                                          ///
    ///                       EXECUTE PROPOSAL                   ///
    ///                                                          ///

    /// @notice Executes a proposal
    /// @param _targets The target addresses to call
    /// @param _values The ETH values of each call
    /// @param _calldatas The calldata of each call
    /// @param _descriptionHash The hash of the description
    /// @param _proposer The proposal creator
    function execute(
        address[] calldata _targets,
        uint256[] calldata _values,
        bytes[] calldata _calldatas,
        bytes32 _descriptionHash,
        address _proposer
    ) external payable returns (bytes32) {
        // Get the proposal id
        bytes32 proposalId = hashProposal(_targets, _values, _calldatas, _descriptionHash, _proposer);

        // Ensure the proposal is queued
        if (state(proposalId) != ProposalState.Queued) revert PROPOSAL_NOT_QUEUED(proposalId);

        // Mark the proposal as executed
        proposals[proposalId].executed = true;

        // Execute the proposal
        settings.treasury.execute{ value: msg.value }(_targets, _values, _calldatas, _descriptionHash, _proposer);

        emit ProposalExecuted(proposalId);

        return proposalId;
    }

    ///                                                          ///
    ///                        CANCEL PROPOSAL                   ///
    ///                                                          ///

    /// @notice Cancels a proposal
    /// @param _proposalId The proposal id
    function cancel(bytes32 _proposalId) external {
        // Ensure the proposal hasn't been executed
        if (state(_proposalId) == ProposalState.Executed) revert PROPOSAL_ALREADY_EXECUTED();

        // Get a copy of the proposal
        Proposal memory proposal = proposals[_proposalId];

        // Cannot realistically underflow and `getVotes` would revert
        unchecked {
            // Ensure the caller is the proposer or the proposer's voting weight has dropped below the proposal threshold
            if (msg.sender != proposal.proposer && getVotes(proposal.proposer, block.timestamp - 1) >= proposal.proposalThreshold)
                revert INVALID_CANCEL();
        }

        // Update the proposal as canceled
        proposals[_proposalId].canceled = true;

        // If the proposal was queued:
        if (settings.treasury.isQueued(_proposalId)) {
            // Cancel the proposal
            settings.treasury.cancel(_proposalId);
        }

        emit ProposalCanceled(_proposalId);
    }

    ///                                                          ///
    ///                        VETO PROPOSAL                     ///
    ///                                                          ///

    /// @notice Vetoes a proposal
    /// @param _proposalId The proposal id
    function veto(bytes32 _proposalId) external {
        // Ensure the caller is the vetoer
        if (msg.sender != settings.vetoer) revert ONLY_VETOER();

        // Ensure the proposal has not been executed
        if (state(_proposalId) == ProposalState.Executed) revert PROPOSAL_ALREADY_EXECUTED();

        // Get the pointer to the proposal
        Proposal storage proposal = proposals[_proposalId];

        // Update the proposal as vetoed
        proposal.vetoed = true;

        // If the proposal was queued:
        if (settings.treasury.isQueued(_proposalId)) {
            // Cancel the proposal
            settings.treasury.cancel(_proposalId);
        }

        emit ProposalVetoed(_proposalId);
    }

    ///                                                          ///
    ///                        PROPOSAL STATE                    ///
    ///                                                          ///

    /// @notice The state of a proposal
    /// @param _proposalId The proposal id
    function state(bytes32 _proposalId) public view returns (ProposalState) {
        // Get a copy of the proposal
        Proposal memory proposal = proposals[_proposalId];

        // Ensure the proposal exists
        if (proposal.voteStart == 0) revert PROPOSAL_DOES_NOT_EXIST();

        // If the proposal was executed:
        if (proposal.executed) {
            return ProposalState.Executed;

            // Else if the proposal was canceled:
        } else if (proposal.canceled) {
            return ProposalState.Canceled;

            // Else if the proposal was vetoed:
        } else if (proposal.vetoed) {
            return ProposalState.Vetoed;

            // Else if voting has not started:
        } else if (block.timestamp < proposal.voteStart) {
            return ProposalState.Pending;

            // Else if voting has not ended:
        } else if (block.timestamp < proposal.voteEnd) {
            return ProposalState.Active;

            // Else if the proposal failed (outvoted OR didn't reach quorum):
        } else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < proposal.quorumVotes) {
            return ProposalState.Defeated;

            // Else if the proposal has not been queued:
        } else if (settings.treasury.timestamp(_proposalId) == 0) {
            return ProposalState.Succeeded;

            // Else if the proposal can no longer be executed:
        } else if (settings.treasury.isExpired(_proposalId)) {
            return ProposalState.Expired;

            // Else the proposal is queued
        } else {
            return ProposalState.Queued;
        }
    }

    /// @notice The voting weight of an account at a timestamp
    /// @param _account The account address
    /// @param _timestamp The specific timestamp
    function getVotes(address _account, uint256 _timestamp) public view returns (uint256) {
        return settings.token.getPastVotes(_account, _timestamp);
    }

    /// @notice The current number of votes required to submit a proposal
    function proposalThreshold() public view returns (uint256) {
        unchecked {
            return (settings.token.totalSupply() * settings.proposalThresholdBps) / BPS_PER_100_PERCENT;
        }
    }

    /// @notice The current number of votes required to be in favor of a proposal in order to reach quorum
    function quorum() public view returns (uint256) {
        unchecked {
            return (settings.token.totalSupply() * settings.quorumThresholdBps) / BPS_PER_100_PERCENT;
        }
    }

    /// @notice The data stored for a given proposal
    /// @param _proposalId The proposal id
    function getProposal(bytes32 _proposalId) external view returns (Proposal memory) {
        return proposals[_proposalId];
    }

    /// @notice The timestamp when voting starts for a proposal
    /// @param _proposalId The proposal id
    function proposalSnapshot(bytes32 _proposalId) external view returns (uint256) {
        return proposals[_proposalId].voteStart;
    }

    /// @notice The timestamp when voting ends for a proposal
    /// @param _proposalId The proposal id
    function proposalDeadline(bytes32 _proposalId) external view returns (uint256) {
        return proposals[_proposalId].voteEnd;
    }

    /// @notice The vote counts for a proposal
    /// @param _proposalId The proposal id
    function proposalVotes(bytes32 _proposalId)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        Proposal memory proposal = proposals[_proposalId];

        return (proposal.againstVotes, proposal.forVotes, proposal.abstainVotes);
    }

    /// @notice The timestamp valid to execute a proposal
    /// @param _proposalId The proposal id
    function proposalEta(bytes32 _proposalId) external view returns (uint256) {
        return settings.treasury.timestamp(_proposalId);
    }

    ///                                                          ///
    ///                      GOVERNOR SETTINGS                   ///
    ///                                                          ///

    /// @notice The basis points of the token supply required to create a proposal
    function proposalThresholdBps() external view returns (uint256) {
        return settings.proposalThresholdBps;
    }

    /// @notice The basis points of the token supply required to reach quorum
    function quorumThresholdBps() external view returns (uint256) {
        return settings.quorumThresholdBps;
    }

    /// @notice The amount of time until voting begins after a proposal is created
    function votingDelay() external view returns (uint256) {
        return settings.votingDelay;
    }

    /// @notice The amount of time to vote on a proposal
    function votingPeriod() external view returns (uint256) {
        return settings.votingPeriod;
    }

    /// @notice The address eligible to veto any proposal (address(0) if burned)
    function vetoer() external view returns (address) {
        return settings.vetoer;
    }

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

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

    ///                                                          ///
    ///                       UPDATE SETTINGS                    ///
    ///                                                          ///

    /// @notice Updates the voting delay
    /// @param _newVotingDelay The new voting delay
    function updateVotingDelay(uint256 _newVotingDelay) external onlyOwner {
        if (_newVotingDelay < MIN_VOTING_DELAY || _newVotingDelay > MAX_VOTING_DELAY) revert INVALID_VOTING_DELAY();

        emit VotingDelayUpdated(settings.votingDelay, _newVotingDelay);

        settings.votingDelay = uint48(_newVotingDelay);
    }

    /// @notice Updates the voting period
    /// @param _newVotingPeriod The new voting period
    function updateVotingPeriod(uint256 _newVotingPeriod) external onlyOwner {
        if (_newVotingPeriod < MIN_VOTING_PERIOD || _newVotingPeriod > MAX_VOTING_PERIOD) revert INVALID_VOTING_PERIOD();

        emit VotingPeriodUpdated(settings.votingPeriod, _newVotingPeriod);

        settings.votingPeriod = uint48(_newVotingPeriod);
    }

    /// @notice Updates the minimum proposal threshold
    /// @param _newProposalThresholdBps The new proposal threshold basis points
    function updateProposalThresholdBps(uint256 _newProposalThresholdBps) external onlyOwner {
        if (
            _newProposalThresholdBps < MIN_PROPOSAL_THRESHOLD_BPS ||
            _newProposalThresholdBps > MAX_PROPOSAL_THRESHOLD_BPS ||
            _newProposalThresholdBps >= settings.quorumThresholdBps
        ) revert INVALID_PROPOSAL_THRESHOLD_BPS();

        emit ProposalThresholdBpsUpdated(settings.proposalThresholdBps, _newProposalThresholdBps);

        settings.proposalThresholdBps = uint16(_newProposalThresholdBps);
    }

    /// @notice Updates the minimum quorum threshold
    /// @param _newQuorumVotesBps The new quorum votes basis points
    function updateQuorumThresholdBps(uint256 _newQuorumVotesBps) external onlyOwner {
        if (
            _newQuorumVotesBps < MIN_QUORUM_THRESHOLD_BPS ||
            _newQuorumVotesBps > MAX_QUORUM_THRESHOLD_BPS ||
            settings.proposalThresholdBps >= _newQuorumVotesBps
        ) revert INVALID_QUORUM_THRESHOLD_BPS();

        emit QuorumVotesBpsUpdated(settings.quorumThresholdBps, _newQuorumVotesBps);

        settings.quorumThresholdBps = uint16(_newQuorumVotesBps);
    }

    /// @notice Updates the vetoer
    /// @param _newVetoer The new vetoer address
    function updateVetoer(address _newVetoer) external onlyOwner {
        if (_newVetoer == address(0)) revert ADDRESS_ZERO();

        emit VetoerUpdated(settings.vetoer, _newVetoer);

        settings.vetoer = _newVetoer;
    }

    /// @notice Burns the vetoer
    function burnVetoer() external onlyOwner {
        emit VetoerUpdated(settings.vetoer, address(0));

        delete settings.vetoer;
    }

    ///                                                          ///
    ///                       GOVERNOR UPGRADE                   ///
    ///                                                          ///

    /// @notice Ensures the caller is authorized to upgrade the contract and that the new implementation is valid
    /// @dev This function is called in `upgradeTo` & `upgradeToAndCall`
    /// @param _newImpl The new implementation address
    function _authorizeUpgrade(address _newImpl) internal view override onlyOwner {
        // Ensure the new implementation is a registered upgrade
        if (!manager.isRegisteredUpgrade(_getImplementation(), _newImpl)) revert INVALID_UPGRADE(_newImpl);
    }
}

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

pragma solidity ^0.8.0;

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

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

pragma solidity ^0.8.0;

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

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

import { IUUPS } from "../../lib/interfaces/IUUPS.sol";
import { IOwnable } from "../../lib/utils/Ownable.sol";
import { IEIP712 } from "../../lib/utils/EIP712.sol";
import { GovernorTypesV1 } from "./types/GovernorTypesV1.sol";
import { IManager } from "../../manager/IManager.sol";

/// @title IGovernor
/// @author Rohan Kulkarni
/// @notice The external Governor events, errors and functions
interface IGovernor is IUUPS, IOwnable, IEIP712, GovernorTypesV1 {
    ///                                                          ///
    ///                            EVENTS                        ///
    ///                                                          ///

    /// @notice Emitted when a proposal is created
    event ProposalCreated(
        bytes32 proposalId,
        address[] targets,
        uint256[] values,
        bytes[] calldatas,
        string description,
        bytes32 descriptionHash,
        Proposal proposal
    );

    /// @notice Emitted when a proposal is queued
    event ProposalQueued(bytes32 proposalId, uint256 eta);

    /// @notice Emitted when a proposal is executed
    /// @param proposalId The proposal id
    event ProposalExecuted(bytes32 proposalId);

    /// @notice Emitted when a proposal is canceled
    event ProposalCanceled(bytes32 proposalId);

    /// @notice Emitted when a proposal is vetoed
    event ProposalVetoed(bytes32 proposalId);

    /// @notice Emitted when a vote is casted for a proposal
    event VoteCast(address voter, bytes32 proposalId, uint256 support, uint256 weight, string reason);

    /// @notice Emitted when the governor's voting delay is updated
    event VotingDelayUpdated(uint256 prevVotingDelay, uint256 newVotingDelay);

    /// @notice Emitted when the governor's voting period is updated
    event VotingPeriodUpdated(uint256 prevVotingPeriod, uint256 newVotingPeriod);

    /// @notice Emitted when the basis points of the governor's proposal threshold is updated
    event ProposalThresholdBpsUpdated(uint256 prevBps, uint256 newBps);

    /// @notice Emitted when the basis points of the governor's quorum votes is updated
    event QuorumVotesBpsUpdated(uint256 prevBps, uint256 newBps);

    //// @notice Emitted when the governor's vetoer is updated
    event VetoerUpdated(address prevVetoer, address newVetoer);

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

    error INVALID_PROPOSAL_THRESHOLD_BPS();

    error INVALID_QUORUM_THRESHOLD_BPS();

    error INVALID_VOTING_DELAY();

    error INVALID_VOTING_PERIOD();

    /// @dev Reverts if a proposal already exists
    /// @param proposalId The proposal id
    error PROPOSAL_EXISTS(bytes32 proposalId);

    /// @dev Reverts if a proposal isn't queued
    /// @param proposalId The proposal id
    error PROPOSAL_NOT_QUEUED(bytes32 proposalId);

    /// @dev Reverts if the proposer didn't specify a target address
    error PROPOSAL_TARGET_MISSING();

    /// @dev Reverts if the number of targets, values, and calldatas does not match
    error PROPOSAL_LENGTH_MISMATCH();

    /// @dev Reverts if a proposal didn't succeed
    error PROPOSAL_UNSUCCESSFUL();

    /// @dev Reverts if a proposal was already executed
    error PROPOSAL_ALREADY_EXECUTED();

    /// @dev Reverts if a specified proposal doesn't exist
    error PROPOSAL_DOES_NOT_EXIST();

    /// @dev Reverts if the proposer's voting weight is below the proposal threshold
    error BELOW_PROPOSAL_THRESHOLD();

    /// @dev Reverts if a vote was prematurely casted
    error VOTING_NOT_STARTED();

    /// @dev Reverts if the caller wasn't the vetoer
    error ONLY_VETOER();

    /// @dev Reverts if the caller already voted
    error ALREADY_VOTED();

    /// @dev Reverts if a proposal was attempted to be canceled incorrectly
    error INVALID_CANCEL();

    /// @dev Reverts if a vote was attempted to be casted incorrectly
    error INVALID_VOTE();

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

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

    /// @notice Initializes a DAO's governor
    /// @param treasury The DAO's treasury address
    /// @param token The DAO's governance token address
    /// @param vetoer The address eligible to veto proposals
    /// @param votingDelay The voting delay
    /// @param votingPeriod The voting period
    /// @param proposalThresholdBps The proposal threshold basis points
    /// @param quorumThresholdBps The quorum threshold basis points
    function initialize(
        address treasury,
        address token,
        address vetoer,
        uint256 votingDelay,
        uint256 votingPeriod,
        uint256 proposalThresholdBps,
        uint256 quorumThresholdBps
    ) external;

    /// @notice Creates a proposal
    /// @param targets The target addresses to call
    /// @param values The ETH values of each call
    /// @param calldatas The calldata of each call
    /// @param description The proposal description
    function propose(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        string memory description
    ) external returns (bytes32);

    /// @notice Casts a vote
    /// @param proposalId The proposal id
    /// @param support The support value (0 = Against, 1 = For, 2 = Abstain)
    function castVote(bytes32 proposalId, uint256 support) external returns (uint256);

    /// @notice Casts a vote with a reason
    /// @param proposalId The proposal id
    /// @param support The support value (0 = Against, 1 = For, 2 = Abstain)
    /// @param reason The vote reason
    function castVoteWithReason(
        bytes32 proposalId,
        uint256 support,
        string memory reason
    ) external returns (uint256);

    /// @notice Casts a signed vote
    /// @param voter The voter address
    /// @param proposalId The proposal id
    /// @param support The support value (0 = Against, 1 = For, 2 = Abstain)
    /// @param deadline The signature deadline
    /// @param v The 129th byte and chain id of the signature
    /// @param r The first 64 bytes of the signature
    /// @param s Bytes 64-128 of the signature
    function castVoteBySig(
        address voter,
        bytes32 proposalId,
        uint256 support,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256);

    /// @notice Queues a proposal
    /// @param proposalId The proposal id
    function queue(bytes32 proposalId) external returns (uint256 eta);

    /// @notice Executes a proposal
    /// @param targets The target addresses to call
    /// @param values The ETH values of each call
    /// @param calldatas The calldata of each call
    /// @param descriptionHash The hash of the description
    /// @param proposer The proposal creator
    function execute(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash,
        address proposer
    ) external payable returns (bytes32);

    /// @notice Cancels a proposal
    /// @param proposalId The proposal id
    function cancel(bytes32 proposalId) external;

    /// @notice Vetoes a proposal
    /// @param proposalId The proposal id
    function veto(bytes32 proposalId) external;

    /// @notice The state of a proposal
    /// @param proposalId The proposal id
    function state(bytes32 proposalId) external view returns (ProposalState);

    /// @notice The voting weight of an account at a timestamp
    /// @param account The account address
    /// @param timestamp The specific timestamp
    function getVotes(address account, uint256 timestamp) external view returns (uint256);

    /// @notice The current number of votes required to submit a proposal
    function proposalThreshold() external view returns (uint256);

    /// @notice The current number of votes required to be in favor of a proposal in order to reach quorum
    function quorum() external view returns (uint256);

    /// @notice The details of a proposal
    /// @param proposalId The proposal id
    function getProposal(bytes32 proposalId) external view returns (Proposal memory);

    /// @notice The timestamp when voting starts for a proposal
    /// @param proposalId The proposal id
    function proposalSnapshot(bytes32 proposalId) external view returns (uint256);

    /// @notice The timestamp when voting ends for a proposal
    /// @param proposalId The proposal id
    function proposalDeadline(bytes32 proposalId) external view returns (uint256);

    /// @notice The vote counts for a proposal
    /// @param proposalId The proposal id
    function proposalVotes(bytes32 proposalId)
        external
        view
        returns (
            uint256 againstVotes,
            uint256 forVotes,
            uint256 abstainVotes
        );

    /// @notice The timestamp valid to execute a proposal
    /// @param proposalId The proposal id
    function proposalEta(bytes32 proposalId) external view returns (uint256);

    /// @notice The minimum basis points of the total token supply required to submit a proposal
    function proposalThresholdBps() external view returns (uint256);

    /// @notice The minimum basis points of the total token supply required to reach quorum
    function quorumThresholdBps() external view returns (uint256);

    /// @notice The amount of time until voting begins after a proposal is created
    function votingDelay() external view returns (uint256);

    /// @notice The amount of time to vote on a proposal
    function votingPeriod() external view returns (uint256);

    /// @notice The address eligible to veto any proposal (address(0) if burned)
    function vetoer() external view returns (address);

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

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

    /// @notice Updates the voting delay
    /// @param newVotingDelay The new voting delay
    function updateVotingDelay(uint256 newVotingDelay) external;

    /// @notice Updates the voting period
    /// @param newVotingPeriod The new voting period
    function updateVotingPeriod(uint256 newVotingPeriod) external;

    /// @notice Updates the minimum proposal threshold
    /// @param newProposalThresholdBps The new proposal threshold basis points
    function updateProposalThresholdBps(uint256 newProposalThresholdBps) external;

    /// @notice Updates the minimum quorum threshold
    /// @param newQuorumVotesBps The new quorum votes basis points
    function updateQuorumThresholdBps(uint256 newQuorumVotesBps) external;

    /// @notice Updates the vetoer
    /// @param newVetoer The new vetoer addresss
    function updateVetoer(address newVetoer) external;

    /// @notice Burns the vetoer
    function burnVetoer() external;

    /// @notice The EIP-712 typehash to vote with a signature
    function VOTE_TYPEHASH() external view returns (bytes32);
}

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

/// @title ProposalHasher
/// @author tbtstl
/// @notice Helper contract to ensure proposal hashing functions are unified
abstract contract ProposalHasher {
    ///                                                          ///
    ///                         HASH PROPOSAL                    ///
    ///                                                          ///

    /// @notice Hashes a proposal's details into a proposal id
    /// @param _targets The target addresses to call
    /// @param _values The ETH values of each call
    /// @param _calldatas The calldata of each call
    /// @param _descriptionHash The hash of the description
    /// @param _proposer The original proposer of the transaction
    function hashProposal(
        address[] memory _targets,
        uint256[] memory _values,
        bytes[] memory _calldatas,
        bytes32 _descriptionHash,
        address _proposer
    ) public pure returns (bytes32) {
        return keccak256(abi.encode(_targets, _values, _calldatas, _descriptionHash, _proposer));
    }
}

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

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

/// @title GovernorStorageV1
/// @author Rohan Kulkarni
/// @notice The Governor storage contract
contract GovernorStorageV1 is GovernorTypesV1 {
    /// @notice The governor settings
    Settings internal settings;

    /// @notice The details of a proposal
    /// @dev Proposal Id => Proposal
    mapping(bytes32 => Proposal) internal proposals;

    /// @notice If a user has voted on a proposal
    /// @dev Proposal Id => User => Has Voted
    mapping(bytes32 => mapping(address => bool)) internal hasVoted;
}

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

import { Token } from "../../../token/Token.sol";
import { Treasury } from "../../treasury/Treasury.sol";

/// @title GovernorTypesV1
/// @author Rohan Kulkarni
/// @notice The Governor custom data types
interface GovernorTypesV1 {
    /// @notice The governor settings
    /// @param token The DAO governance token
    /// @param proposalThresholdBps The basis points of the token supply required to create a proposal
    /// @param quorumThresholdBps The basis points of the token supply required to reach quorum
    /// @param treasury The DAO treasury
    /// @param votingDelay The time delay to vote on a created proposal
    /// @param votingPeriod The time period to vote on a proposal
    /// @param vetoer The address with the ability to veto proposals
    struct Settings {
        Token token;
        uint16 proposalThresholdBps;
        uint16 quorumThresholdBps;
        Treasury treasury;
        uint48 votingDelay;
        uint48 votingPeriod;
        address vetoer;
    }

    /// @notice A governance proposal
    /// @param proposer The proposal creator
    /// @param timeCreated The timestamp that the proposal was created
    /// @param againstVotes The number of votes against
    /// @param forVotes The number of votes in favor
    /// @param abstainVotes The number of votes abstained
    /// @param voteStart The timestamp that voting starts
    /// @param voteEnd The timestamp that voting ends
    /// @param proposalThreshold The proposal threshold when the proposal was created
    /// @param quorumVotes The quorum threshold when the proposal was created
    /// @param executed If the proposal was executed
    /// @param canceled If the proposal was canceled
    /// @param vetoed If the proposal was vetoed
    struct Proposal {
        address proposer;
        uint32 timeCreated;
        uint32 againstVotes;
        uint32 forVotes;
        uint32 abstainVotes;
        uint32 voteStart;
        uint32 voteEnd;
        uint32 proposalThreshold;
        uint32 quorumVotes;
        bool executed;
        bool canceled;
        bool vetoed;
    }

    /// @notice The proposal state type
    enum ProposalState {
        Pending,
        Active,
        Canceled,
        Defeated,
        Succeeded,
        Queued,
        Expired,
        Executed,
        Vetoed
    }
}

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

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

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

    /// @notice Emitted when a transaction is scheduled
    event TransactionScheduled(bytes32 proposalId, uint256 timestamp);

    /// @notice Emitted when a transaction is canceled
    event TransactionCanceled(bytes32 proposalId);

    /// @notice Emitted when a transaction is executed
    event TransactionExecuted(bytes32 proposalId, address[] targets, uint256[] values, bytes[] payloads);

    /// @notice Emitted when the transaction delay is updated
    event DelayUpdated(uint256 prevDelay, uint256 newDelay);

    /// @notice Emitted when the grace period is updated
    event GracePeriodUpdated(uint256 prevGracePeriod, uint256 newGracePeriod);

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

    /// @dev Reverts if tx was already queued
    error PROPOSAL_ALREADY_QUEUED();

    /// @dev Reverts if tx was not queued
    error PROPOSAL_NOT_QUEUED();

    /// @dev Reverts if a tx isn't ready to execute
    /// @param proposalId The proposal id
    error EXECUTION_NOT_READY(bytes32 proposalId);

    /// @dev Reverts if a tx failed
    /// @param txIndex The index of the tx
    error EXECUTION_FAILED(uint256 txIndex);

    /// @dev Reverts if execution was attempted after the grace period
    error EXECUTION_EXPIRED();

    /// @dev Reverts if the caller was not the treasury itself
    error ONLY_TREASURY();

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

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

    /// @notice Initializes a DAO's treasury
    /// @param governor The governor address
    /// @param timelockDelay The time delay to execute a queued transaction
    function initialize(address governor, uint256 timelockDelay) external;

    /// @notice The timestamp that a proposal is valid to execute
    /// @param proposalId The proposal id
    function timestamp(bytes32 proposalId) external view returns (uint256);

    /// @notice If a proposal has been queued
    /// @param proposalId The proposal ids
    function isQueued(bytes32 proposalId) external view returns (bool);

    /// @notice If a proposal is ready to execute (does not consider if a proposal has expired)
    /// @param proposalId The proposal id
    function isReady(bytes32 proposalId) external view returns (bool);

    /// @notice If a proposal has expired to execute
    /// @param proposalId The proposal id
    function isExpired(bytes32 proposalId) external view returns (bool);

    /// @notice Schedules a proposal for execution
    /// @param proposalId The proposal id
    function queue(bytes32 proposalId) external returns (uint256 eta);

    /// @notice Removes a queued proposal
    /// @param proposalId The proposal id
    function cancel(bytes32 proposalId) external;

    /// @notice Executes a queued proposal
    /// @param targets The target addresses to call
    /// @param values The ETH values of each call
    /// @param calldatas The calldata of each call
    /// @param descriptionHash The hash of the description
    /// @param proposer The proposal creator
    function execute(
        address[] calldata targets,
        uint256[] calldata values,
        bytes[] calldata calldatas,
        bytes32 descriptionHash,
        address proposer
    ) external payable;

    /// @notice The time delay to execute a queued transaction
    function delay() external view returns (uint256);

    /// @notice The time period to execute a transaction
    function gracePeriod() external view returns (uint256);

    /// @notice Updates the time delay
    /// @param newDelay The new time delay
    function updateDelay(uint256 newDelay) external;

    /// @notice Updates the grace period
    /// @param newGracePeriod The grace period
    function updateGracePeriod(uint256 newGracePeriod) external;
}

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

import { UUPS } from "../../lib/proxy/UUPS.sol";
import { Ownable } from "../../lib/utils/Ownable.sol";
import { ERC721TokenReceiver, ERC1155TokenReceiver } from "../../lib/utils/TokenReceiver.sol";
import { SafeCast } from "../../lib/utils/SafeCast.sol";

import { TreasuryStorageV1 } from "./storage/TreasuryStorageV1.sol";
import { ITreasury } from "./ITreasury.sol";
import { ProposalHasher } from "../governor/ProposalHasher.sol";
import { IManager } from "../../manager/IManager.sol";
import { VersionedContract } from "../../VersionedContract.sol";

/// @title Treasury
/// @author Rohan Kulkarni
/// @notice A DAO's treasury and transaction executor
/// @custom:repo github.com/ourzora/nouns-protocol 
/// Modified from:
/// - OpenZeppelin Contracts v4.7.3 (governance/TimelockController.sol)
/// - NounsDAOExecutor.sol commit 2cbe6c7 - licensed under the BSD-3-Clause license.
contract Treasury is ITreasury, VersionedContract, UUPS, Ownable, ProposalHasher, TreasuryStorageV1 {
    ///                                                          ///
    ///                         CONSTANTS                        ///
    ///                                                          ///

    /// @notice The default grace period setting
    uint128 private constant INITIAL_GRACE_PERIOD = 2 weeks;

    ///                                                          ///
    ///                         IMMUTABLES                       ///
    ///                                                          ///

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

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

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

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

    /// @notice Initializes an instance of a DAO's treasury
    /// @param _governor The DAO's governor address
    /// @param _delay The time delay to execute a queued transaction
    function initialize(address _governor, uint256 _delay) external initializer {
        // Ensure the caller is the contract manager
        if (msg.sender != address(manager)) revert ONLY_MANAGER();

        // Ensure a governor address was provided
        if (_governor == address(0)) revert ADDRESS_ZERO();

        // Grant ownership to the governor
        __Ownable_init(_governor);

        // Store the time delay
        settings.delay = SafeCast.toUint128(_delay);

        // Set the default grace period
        settings.gracePeriod = INITIAL_GRACE_PERIOD;

        emit DelayUpdated(0, _delay);
    }

    ///                                                          ///
    ///                      TRANSACTION STATE                   ///
    ///                                                          ///

    /// @notice The timestamp that a proposal is valid to execute
    /// @param _proposalId The proposal id
    function timestamp(bytes32 _proposalId) external view returns (uint256) {
        return timestamps[_proposalId];
    }

    /// @notice If a queued proposal can no longer be executed
    /// @param _proposalId The proposal id
    function isExpired(bytes32 _proposalId) external view returns (bool) {
        unchecked {
            return block.timestamp > (timestamps[_proposalId] + settings.gracePeriod);
        }
    }

    /// @notice If a proposal is queued
    /// @param _proposalId The proposal id
    function isQueued(bytes32 _proposalId) public view returns (bool) {
        return timestamps[_proposalId] != 0;
    }

    /// @notice If a proposal is ready to execute (does not consider expiration)
    /// @param _proposalId The proposal id
    function isReady(bytes32 _proposalId) public view returns (bool) {
        return timestamps[_proposalId] != 0 && block.timestamp >= timestamps[_proposalId];
    }

    ///                                                          ///
    ///                        QUEUE PROPOSAL                    ///
    ///                                                          ///

    /// @notice Schedules a proposal for execution
    /// @param _proposalId The proposal id
    function queue(bytes32 _proposalId) external onlyOwner returns (uint256 eta) {
        // Ensure the proposal was not already queued
        if (isQueued(_proposalId)) revert PROPOSAL_ALREADY_QUEUED();

        // Cannot realistically overflow
        unchecked {
            // Compute the timestamp that the proposal will be valid to execute
            eta = block.timestamp + settings.delay;
        }

        // Store the timestamp
        timestamps[_proposalId] = eta;

        emit TransactionScheduled(_proposalId, eta);
    }

    ///                                                          ///
    ///                       EXECUTE PROPOSAL                   ///
    ///                                                          ///

    /// @notice Executes a queued proposal
    /// @param _targets The target addresses to call
    /// @param _values The ETH values of each call
    /// @param _calldatas The calldata of each call
    /// @param _descriptionHash The hash of the description
    /// @param _proposer The proposal creator
    function execute(
        address[] calldata _targets,
        uint256[] calldata _values,
        bytes[] calldata _calldatas,
        bytes32 _descriptionHash,
        address _proposer
    ) external payable onlyOwner {
        // Get the proposal id
        bytes32 proposalId = hashProposal(_targets, _values, _calldatas, _descriptionHash, _proposer);

        // Ensure the proposal is ready to execute
        if (!isReady(proposalId)) revert EXECUTION_NOT_READY(proposalId);

        // Remove the proposal from the queue
        delete timestamps[proposalId];

        // Cache the number of targets
        uint256 numTargets = _targets.length;

        // Cannot realistically overflow
        unchecked {
            // For each target:
            for (uint256 i = 0; i < numTargets; ++i) {
                // Execute the transaction
                (bool success, ) = _targets[i].call{ value: _values[i] }(_calldatas[i]);

                // Ensure the transaction succeeded
                if (!success) revert EXECUTION_FAILED(i);
            }
        }

        emit TransactionExecuted(proposalId, _targets, _values, _calldatas);
    }

    ///                                                          ///
    ///                       CANCEL PROPOSAL                    ///
    ///                                                          ///

    /// @notice Removes a queued proposal
    /// @param _proposalId The proposal id
    function cancel(bytes32 _proposalId) external onlyOwner {
        // Ensure the proposal is queued
        if (!isQueued(_proposalId)) revert PROPOSAL_NOT_QUEUED();

        // Remove the proposal from the queue
        delete timestamps[_proposalId];

        emit TransactionCanceled(_proposalId);
    }

    ///                                                          ///
    ///                      TREASURY SETTINGS                   ///
    ///                                                          ///

    /// @notice The time delay to execute a queued transaction
    function delay() external view returns (uint256) {
        return settings.delay;
    }

    /// @notice The time period to execute a proposal
    function gracePeriod() external view returns (uint256) {
        return settings.gracePeriod;
    }

    ///                                                          ///
    ///                       UPDATE SETTINGS                    ///
    ///                                                          ///

    /// @notice Updates the transaction delay
    /// @param _newDelay The new time delay
    function updateDelay(uint256 _newDelay) external {
        // Ensure the caller is the treasury itself
        if (msg.sender != address(this)) revert ONLY_TREASURY();

        emit DelayUpdated(settings.delay, _newDelay);

        // Update the delay
        settings.delay = SafeCast.toUint128(_newDelay);
    }

    /// @notice Updates the execution grace period
    /// @param _newGracePeriod The new grace period
    function updateGracePeriod(uint256 _newGracePeriod) external {
        // Ensure the caller is the treasury itself
        if (msg.sender != address(this)) revert ONLY_TREASURY();

        emit GracePeriodUpdated(settings.gracePeriod, _newGracePeriod);

        // Update the grace period
        settings.gracePeriod = SafeCast.toUint128(_newGracePeriod);
    }

    ///                                                          ///
    ///                        RECEIVE TOKENS                    ///
    ///                                                          ///

    /// @dev Accepts all ERC-721 transfers
    function onERC721Received(
        address,
        address,
        uint256,
        bytes memory
    ) public pure returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }

    /// @dev Accepts all ERC-1155 single id transfers
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) public pure returns (bytes4) {
        return ERC1155TokenReceiver.onERC1155Received.selector;
    }

    /// @dev Accept all ERC-1155 batch id transfers
    function onERC1155BatchReceived(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) public pure returns (bytes4) {
        return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
    }

    /// @dev Accepts ETH transfers
    receive() external payable {}

    ///                                                          ///
    ///                       TREASURY UPGRADE                   ///
    ///                                                          ///

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

        // Ensure the new implementation is a registered upgrade
        if (!manager.isRegisteredUpgrade(_getImplementation(), _newImpl)) revert INVALID_UPGRADE(_newImpl);
    }
}

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

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

/// @notice TreasuryStorageV1
/// @author Rohan Kulkarni
/// @notice The Treasury storage contract
contract TreasuryStorageV1 is TreasuryTypesV1 {
    /// @notice The treasury settings
    Settings internal settings;

    /// @notice The timestamp that a queued proposal is ready to execute
    /// @dev Proposal Id => Timestamp
    mapping(bytes32 => uint256) internal timestamps;
}

File 13 of 40 : TreasuryTypesV1.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @notice TreasuryTypesV1
/// @author Rohan Kulkarni
/// @notice The treasury's custom data types
contract TreasuryTypesV1 {
    /// @notice The settings type
    /// @param gracePeriod The time period to execute a proposal
    /// @param delay The time delay to execute a queued transaction
    struct Settings {
        uint128 gracePeriod;
        uint128 delay;
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            _upgradeToAndCall(_newImpl, _data, _forceCall);
        }
    }

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

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

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

        emit Upgraded(_newImpl);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return balances[_owner];
    }

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

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

        return owner;
    }

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

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

        tokenApprovals[_tokenId] = _to;

        emit Approval(owner, _to, _tokenId);
    }

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

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

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

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

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

        _beforeTokenTransfer(_from, _to, _tokenId);

        unchecked {
            --balances[_from];

            ++balances[_to];
        }

        owners[_tokenId] = _to;

        delete tokenApprovals[_tokenId];

        emit Transfer(_from, _to, _tokenId);

        _afterTokenTransfer(_from, _to, _tokenId);
    }

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

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

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

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

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

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

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

        unchecked {
            ++balances[_to];
        }

        owners[_tokenId] = _to;

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

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

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

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

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

        unchecked {
            --balances[owner];
        }

        delete owners[_tokenId];

        delete tokenApprovals[_tokenId];

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            return accountCheckpoints[low].votes;
        }
    }

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

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

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

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

        // Used to store the digest
        bytes32 digest;

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

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

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

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

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

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

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

        emit DelegateChanged(_from, prevDelegate, _to);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return verifyCallResult(success, returndata);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        _initialized = 1;

        if (isTopLevelCall) {
            _initializing = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;

            emit Initialized(1);
        }
    }

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

        _initialized = _version;

        _initializing = true;

        _;

        _initializing = false;

        emit Initialized(_version);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        _owner = _newOwner;

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

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

        emit OwnerPending(_owner, _newOwner);
    }

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

        _owner = _pendingOwner;

        delete _pendingOwner;
    }

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

        delete _pendingOwner;
    }
}

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

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

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

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

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

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

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

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

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

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

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

        _status = _ENTERED;

        _;

        _status = _NOT_ENTERED;
    }
}

File 31 of 40 : SafeCast.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @notice Modified from OpenZeppelin Contracts v4.7.3 (utils/math/SafeCast.sol)
/// - Uses custom error `UNSAFE_CAST()`
library SafeCast {
    error UNSAFE_CAST();

    function toUint128(uint256 x) internal pure returns (uint128) {
        if (x > type(uint128).max) revert UNSAFE_CAST();

        return uint128(x);
    }

    function toUint64(uint256 x) internal pure returns (uint64) {
        if (x > type(uint64).max) revert UNSAFE_CAST();

        return uint64(x);
    }

    function toUint48(uint256 x) internal pure returns (uint48) {
        if (x > type(uint48).max) revert UNSAFE_CAST();

        return uint48(x);
    }

    function toUint40(uint256 x) internal pure returns (uint40) {
        if (x > type(uint40).max) revert UNSAFE_CAST();

        return uint40(x);
    }

    function toUint32(uint256 x) internal pure returns (uint32) {
        if (x > type(uint32).max) revert UNSAFE_CAST();

        return uint32(x);
    }

    function toUint16(uint256 x) internal pure returns (uint16) {
        if (x > type(uint16).max) revert UNSAFE_CAST();

        return uint16(x);
    }

    function toUint8(uint256 x) internal pure returns (uint8) {
        if (x > type(uint8).max) revert UNSAFE_CAST();

        return uint8(x);
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /// @notice Emitted when minters are updated
    /// @param minter Address of added or removed minter
    /// @param allowed Whether address is allowed to mint
    event MinterUpdated(address minter, bool allowed);

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

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

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

    /// @dev Reverts if the caller was not a minter
    error ONLY_AUCTION_OR_MINTER();

    /// @dev Reverts if the caller was not the token owner
    error ONLY_TOKEN_OWNER();

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

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

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

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

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

    /// @notice Mints tokens to the recipient and handles founder vesting
    function mintTo(address recipient) external returns (uint256 tokenId);

    /// @notice Mints the specified amount of tokens to the recipient and handles founder vesting
    function mintBatchTo(uint256 amount, address recipient) external returns (uint256[] memory tokenIds);

    /// @notice Burns a token owned by the caller
    /// @param tokenId The ERC-721 token id
    function burn(uint256 tokenId) external;

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

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

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

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

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

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

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

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

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

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

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

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

    /// @notice Update minters
    /// @param _minters Array of structs containing address status as a minter
    function updateMinters(MinterParams[] calldata _minters) external;

    /// @notice Check if an address is a minter
    /// @param _minter Address to check
    function isMinter(address _minter) external view returns (bool);

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

File 35 of 40 : Token.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

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

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

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

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

    /// @notice Reverts if caller is not an authorized minter
    modifier onlyAuctionOrMinter() {
        if (msg.sender != settings.auction && !minter[msg.sender]) {
            revert ONLY_AUCTION_OR_MINTER();
        }

        _;
    }

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

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

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

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

        // Initialize the reentrancy guard
        __ReentrancyGuard_init();

        // Setup ownable
        __Ownable_init(_initialOwner);

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

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

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

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

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

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

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

        uint8 numFoundersAdded = 0;

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

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

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

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

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

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

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

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

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

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

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

                    emit MintScheduled(baseTokenId, founderId, newFounder);

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

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

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

            return _tokenId;
        }
    }

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

    /// @notice Mints tokens to the caller and handles founder vesting
    function mint() external nonReentrant onlyAuctionOrMinter returns (uint256 tokenId) {
        tokenId = _mintWithVesting(msg.sender);
    }

    /// @notice Mints tokens to the recipient and handles founder vesting
    function mintTo(address recipient) external nonReentrant onlyAuctionOrMinter returns (uint256 tokenId) {
        tokenId = _mintWithVesting(recipient);
    }

    /// @notice Mints the specified amount of tokens to the recipient and handles founder vesting
    function mintBatchTo(uint256 amount, address recipient) external nonReentrant onlyAuctionOrMinter returns (uint256[] memory tokenIds) {
        tokenIds = new uint256[](amount);
        for (uint256 i = 0; i < amount; ) {
            tokenIds[i] = _mintWithVesting(recipient);
            unchecked {
                ++i;
            }
        }
    }

    function _mintWithVesting(address recipient) internal returns (uint256 tokenId) {
        // Cannot realistically overflow
        unchecked {
            do {
                // Get the next token to mint
                tokenId = settings.mintCount++;

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

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

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

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

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

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

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

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

            return true;

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

            return false;
        }
    }

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

    /// @notice Burns a token owned by the caller
    /// @param _tokenId The ERC-721 token id
    function burn(uint256 _tokenId) external onlyAuctionOrMinter {
        if (ownerOf(_tokenId) != msg.sender) {
            revert ONLY_TOKEN_OWNER();
        }

        _burn(_tokenId);
    }

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

        unchecked {
            --settings.totalSupply;
        }
    }

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

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

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

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

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

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

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

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

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

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

        return founders;
    }

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

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

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

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

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

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

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

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

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

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

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

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

                    emit MintUnscheduled(baseTokenId, i, cachedFounder);

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

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

        _addFounders(newFounders);
    }

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

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

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

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

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

    /// @notice Update minters
    /// @param _minters Array of structs containing address status as a minter
    function updateMinters(MinterParams[] calldata _minters) external onlyOwner {
        // Update each minter
        for (uint256 i; i < _minters.length; ++i) {
            // Skip if the minter is already set to the correct value
            if (minter[_minters[i].minter] == _minters[i].allowed) continue;

            emit MinterUpdated(_minters[i].minter, _minters[i].allowed);

            // Update the minter
            minter[_minters[i].minter] = _minters[i].allowed;
        }
    }

    /// @notice Check if an address is a minter
    /// @param _minter Address to check
    function isMinter(address _minter) external view returns (bool) {
        return minter[_minter];
    }

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 38 of 40 : TokenStorageV2.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

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

/// @title TokenStorageV2
/// @author James Geary
/// @notice The Token storage contract
contract TokenStorageV2 is TokenTypesV2 {
    /// @notice The minter status of an address
    mapping(address => bool) public minter;
}

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

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

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

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

File 40 of 40 : TokenTypesV2.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title TokenTypesV2
/// @author James Geary
/// @notice The Token custom data types
interface TokenTypesV2 {
    struct MinterParams {
        address minter;
        bool allowed;
    }
}

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

Contract ABI

[{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"ADDRESS_ZERO","type":"error"},{"inputs":[],"name":"ALREADY_INITIALIZED","type":"error"},{"inputs":[],"name":"ALREADY_VOTED","type":"error"},{"inputs":[],"name":"BELOW_PROPOSAL_THRESHOLD","type":"error"},{"inputs":[],"name":"DELEGATE_CALL_FAILED","type":"error"},{"inputs":[],"name":"EXPIRED_SIGNATURE","type":"error"},{"inputs":[],"name":"INITIALIZING","type":"error"},{"inputs":[],"name":"INVALID_CANCEL","type":"error"},{"inputs":[],"name":"INVALID_PROPOSAL_THRESHOLD_BPS","type":"error"},{"inputs":[],"name":"INVALID_QUORUM_THRESHOLD_BPS","type":"error"},{"inputs":[],"name":"INVALID_SIGNATURE","type":"error"},{"inputs":[],"name":"INVALID_TARGET","type":"error"},{"inputs":[{"internalType":"address","name":"impl","type":"address"}],"name":"INVALID_UPGRADE","type":"error"},{"inputs":[],"name":"INVALID_VOTE","type":"error"},{"inputs":[],"name":"INVALID_VOTING_DELAY","type":"error"},{"inputs":[],"name":"INVALID_VOTING_PERIOD","type":"error"},{"inputs":[],"name":"NOT_INITIALIZING","type":"error"},{"inputs":[],"name":"ONLY_CALL","type":"error"},{"inputs":[],"name":"ONLY_DELEGATECALL","type":"error"},{"inputs":[],"name":"ONLY_MANAGER","type":"error"},{"inputs":[],"name":"ONLY_OWNER","type":"error"},{"inputs":[],"name":"ONLY_PENDING_OWNER","type":"error"},{"inputs":[],"name":"ONLY_PROXY","type":"error"},{"inputs":[],"name":"ONLY_UUPS","type":"error"},{"inputs":[],"name":"ONLY_VETOER","type":"error"},{"inputs":[],"name":"PROPOSAL_ALREADY_EXECUTED","type":"error"},{"inputs":[],"name":"PROPOSAL_DOES_NOT_EXIST","type":"error"},{"inputs":[{"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"PROPOSAL_EXISTS","type":"error"},{"inputs":[],"name":"PROPOSAL_LENGTH_MISMATCH","type":"error"},{"inputs":[{"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"PROPOSAL_NOT_QUEUED","type":"error"},{"inputs":[],"name":"PROPOSAL_TARGET_MISSING","type":"error"},{"inputs":[],"name":"PROPOSAL_UNSUCCESSFUL","type":"error"},{"inputs":[],"name":"UNSAFE_CAST","type":"error"},{"inputs":[],"name":"UNSUPPORTED_UUID","type":"error"},{"inputs":[],"name":"VOTING_NOT_STARTED","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"canceledOwner","type":"address"}],"name":"OwnerCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnerPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"ProposalCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"},{"indexed":false,"internalType":"address[]","name":"targets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"},{"indexed":false,"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"indexed":false,"internalType":"bytes32","name":"descriptionHash","type":"bytes32"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint32","name":"timeCreated","type":"uint32"},{"internalType":"uint32","name":"againstVotes","type":"uint32"},{"internalType":"uint32","name":"forVotes","type":"uint32"},{"internalType":"uint32","name":"abstainVotes","type":"uint32"},{"internalType":"uint32","name":"voteStart","type":"uint32"},{"internalType":"uint32","name":"voteEnd","type":"uint32"},{"internalType":"uint32","name":"proposalThreshold","type":"uint32"},{"internalType":"uint32","name":"quorumVotes","type":"uint32"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"bool","name":"canceled","type":"bool"},{"internalType":"bool","name":"vetoed","type":"bool"}],"indexed":false,"internalType":"struct GovernorTypesV1.Proposal","name":"proposal","type":"tuple"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"ProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"eta","type":"uint256"}],"name":"ProposalQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBps","type":"uint256"}],"name":"ProposalThresholdBpsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"ProposalVetoed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBps","type":"uint256"}],"name":"QuorumVotesBpsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"impl","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prevVetoer","type":"address"},{"indexed":false,"internalType":"address","name":"newVetoer","type":"address"}],"name":"VetoerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"support","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"weight","type":"uint256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"VoteCast","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevVotingDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVotingDelay","type":"uint256"}],"name":"VotingDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevVotingPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVotingPeriod","type":"uint256"}],"name":"VotingPeriodUpdated","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PROPOSAL_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_QUORUM_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VOTING_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VOTING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_PROPOSAL_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_QUORUM_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_VOTING_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_VOTING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnVetoer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"},{"internalType":"uint256","name":"_support","type":"uint256"}],"name":"castVote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_voter","type":"address"},{"internalType":"bytes32","name":"_proposalId","type":"bytes32"},{"internalType":"uint256","name":"_support","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"castVoteBySig","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"},{"internalType":"uint256","name":"_support","type":"uint256"},{"internalType":"string","name":"_reason","type":"string"}],"name":"castVoteWithReason","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"bytes[]","name":"_calldatas","type":"bytes[]"},{"internalType":"bytes32","name":"_descriptionHash","type":"bytes32"},{"internalType":"address","name":"_proposer","type":"address"}],"name":"execute","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"getProposal","outputs":[{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint32","name":"timeCreated","type":"uint32"},{"internalType":"uint32","name":"againstVotes","type":"uint32"},{"internalType":"uint32","name":"forVotes","type":"uint32"},{"internalType":"uint32","name":"abstainVotes","type":"uint32"},{"internalType":"uint32","name":"voteStart","type":"uint32"},{"internalType":"uint32","name":"voteEnd","type":"uint32"},{"internalType":"uint32","name":"proposalThreshold","type":"uint32"},{"internalType":"uint32","name":"quorumVotes","type":"uint32"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"bool","name":"canceled","type":"bool"},{"internalType":"bool","name":"vetoed","type":"bool"}],"internalType":"struct GovernorTypesV1.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"bytes[]","name":"_calldatas","type":"bytes[]"},{"internalType":"bytes32","name":"_descriptionHash","type":"bytes32"},{"internalType":"address","name":"_proposer","type":"address"}],"name":"hashProposal","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_vetoer","type":"address"},{"internalType":"uint256","name":"_votingDelay","type":"uint256"},{"internalType":"uint256","name":"_votingPeriod","type":"uint256"},{"internalType":"uint256","name":"_proposalThresholdBps","type":"uint256"},{"internalType":"uint256","name":"_quorumThresholdBps","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalEta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalThresholdBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"bytes[]","name":"_calldatas","type":"bytes[]"},{"internalType":"string","name":"_description","type":"string"}],"name":"propose","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"queue","outputs":[{"internalType":"uint256","name":"eta","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"quorum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorumThresholdBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"safeTransferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"state","outputs":[{"internalType":"enum GovernorTypesV1.ProposalState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newProposalThresholdBps","type":"uint256"}],"name":"updateProposalThresholdBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newQuorumVotesBps","type":"uint256"}],"name":"updateQuorumThresholdBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newVetoer","type":"address"}],"name":"updateVetoer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newVotingDelay","type":"uint256"}],"name":"updateVotingDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newVotingPeriod","type":"uint256"}],"name":"updateVotingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"veto","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vetoer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6102006040819052306080527f4b87515bde17bd1a40e570a7c028fa4b7e66dd1ed9dc7c0cd8fd78d67ca34f2860a052600160c08190526103e860e05260c8610100526107d0610120526101405262dd7c00610160819052610258610180526101a0526127106101c052620059ad3881900390819083398101604081905262000088916200017c565b600054610100900460ff1615801580620000a6575060005460ff1615155b8015620000d65750620000c4306200017660201b62003c141760201c565b80620000d6575060005460ff16600114155b15620000f55760405163439a74c960e01b815260040160405180910390fd5b6000805460ff19166001179055801562000119576000805461ff0019166101001790555b6001600160a01b0382166101e05280156200016e576000805461ff0019169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050620001ae565b3b151590565b6000602082840312156200018f57600080fd5b81516001600160a01b0381168114620001a757600080fd5b9392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e0516156cc620002e1600039600081816112ff0152613e7f015260008181610f1f0152612d38015260008181610a650152818161163d015261386501526000818161045f01528181611614015261383c015260008181610ab9015281816115b901526124bb015260008181610dcd015281816115900152612492015260008181610e81015281816114fc01526136b80152600081816103ab015281816114d3015261368f01526000818161042b015281816114780152613471015260008181610b420152818161144f01526134480152600081816109940152612e35015260008181611a8501528181611adf01528181611cc701528181611d210152611e1401526156cc6000f3fe60806040526004361061034a5760003560e01c806379ba5097116101bb578063c82fbd08116100f7578063eb9019d411610095578063f2fde38b1161006f578063f2fde38b14610e4f578063f990b49114610e6f578063fb6f93f914610ea3578063fc0c546a14610ec357600080fd5b8063eb9019d414610def578063ebfdeacf14610e0f578063ef00ef4314610e2f57600080fd5b8063d8bff440116100d1578063d8bff44014610d45578063e30c397814610d70578063e42eb4f614610d9b578063e48083fe14610dbb57600080fd5b8063c82fbd0814610b30578063cbcda20114610b64578063d14b85b914610ba257600080fd5b8063a0a8e46011610164578063b11262631161013e578063b112626314610aa7578063b58131b014610adb578063c3e5178914610af0578063c4d252f514610b1057600080fd5b8063a0a8e46014610a07578063a64e024a14610a53578063aedbfe3314610a8757600080fd5b8063865229731161019557806386522973146109825780638da5cb5b146109b65780639dcbfd7d146109e757600080fd5b806379ba50971461092d5780637c10dea6146109425780637d5e81e21461096257600080fd5b80633bec7f5b1161028a57806352d1902d1161023357806361d585da1161020d57806361d585da1461087d57806363d61a19146108aa57806370ae92d2146108ca57806375a12d721461090d57600080fd5b806352d1902d1461080957806360e69a7b1461081e57806361d027b31461083157600080fd5b8063430694cf11610264578063430694cf146105d557806348b1aeb4146107c55780634f1ef286146107f657600080fd5b80633bec7f5b146105405780633d24375f1461057357806341f9b62c146105b557600080fd5b8063215809ca116102f75780633644e515116102d15780633644e515146104b65780633659cfe6146104cb5780633932abb1146104eb578063395db2cd1461052057600080fd5b8063215809ca1461044d57806323452b9c146104815780632b4656c81461049657600080fd5b8063177e5a9f11610328578063177e5a9f146103e25780631e5cc3bd146104025780631e7b5d3a1461041957600080fd5b806302a251a31461034f578063032bbc53146103995780631703a018146103cd575b600080fd5b34801561035b57600080fd5b506008547a010000000000000000000000000000000000000000000000000000900465ffffffffffff165b6040519081526020015b60405180910390f35b3480156103a557600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d957600080fd5b50610386610eee565b3480156103ee57600080fd5b506103866103fd366004614777565b610fda565b34801561040e57600080fd5b50610417611074565b005b34801561042557600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b34801561045957600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b34801561048d57600080fd5b50610417611147565b3480156104a257600080fd5b506104176104b13660046147b9565b611219565b3480156104c257600080fd5b506103866119eb565b3480156104d757600080fd5b506104176104e6366004614821565b611a6e565b3480156104f757600080fd5b5060085474010000000000000000000000000000000000000000900465ffffffffffff16610386565b34801561052c57600080fd5b5061041761053b366004614821565b611bc6565b34801561054c57600080fd5b50600754760100000000000000000000000000000000000000000000900461ffff16610386565b34801561057f57600080fd5b5061038661058e366004614777565b6000908152600a602052604090206001015468010000000000000000900463ffffffff1690565b3480156105c157600080fd5b506103866105d0366004614956565b611c9a565b3480156105e157600080fd5b506107b86105f0366004614777565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152506000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821695840195909552780100000000000000000000000000000000000000000000000082048116958301959095527c010000000000000000000000000000000000000000000000000000000090048416606082015260019091015480841660808301526401000000008104841660a0830152680100000000000000008104841660c08301526c010000000000000000000000008104841660e0830152700100000000000000000000000000000000810490931661010082015260ff91830482161515610120820152750100000000000000000000000000000000000000000083048216151561014082015276010000000000000000000000000000000000000000000090920416151561016082015290565b60405161039091906149a6565b3480156107d157600080fd5b5060075474010000000000000000000000000000000000000000900461ffff16610386565b610417610804366004614aac565b611cb0565b34801561081557600080fd5b50610386611dfa565b61038661082c366004614b46565b611e90565b34801561083d57600080fd5b5060085473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610390565b34801561088957600080fd5b5061089d610898366004614777565b612098565b6040516103909190614c28565b3480156108b657600080fd5b506104176108c5366004614777565b612439565b3480156108d657600080fd5b506103866108e5366004614821565b73ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205490565b34801561091957600080fd5b50610386610928366004614c69565b6125c1565b34801561093957600080fd5b506104176125e5565b34801561094e57600080fd5b5061038661095d366004614777565b6126ef565b34801561096e57600080fd5b5061038661097d366004614e0b565b61281a565b34801561098e57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b3480156109c257600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610858565b3480156109f357600080fd5b50610417610a02366004614821565b612b8d565b348015610a1357600080fd5b50604080518082018252600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015290516103909190614f26565b348015610a5f57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610a9357600080fd5b50610386610aa2366004614f39565b612ccb565b348015610ab357600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610ae757600080fd5b50610386612d07565b348015610afc57600080fd5b50610386610b0b366004614fdc565b612db9565b348015610b1c57600080fd5b50610417610b2b366004614777565b613030565b348015610b3c57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610b7057600080fd5b50610386610b7f366004614777565b6000908152600a6020526040902060010154640100000000900463ffffffff1690565b348015610bae57600080fd5b50610d2a610bbd366004614777565b6000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff740100000000000000000000000000000000000000008083048216958401959095527801000000000000000000000000000000000000000000000000820481169583018690527c0100000000000000000000000000000000000000000000000000000000909104811660608301819052600190930154808216608084018190526401000000008204831660a0850152680100000000000000008204831660c08501526c010000000000000000000000008204831660e0850152700100000000000000000000000000000000820490921661010084015260ff94810485161515610120840152750100000000000000000000000000000000000000000081048516151561014084015276010000000000000000000000000000000000000000000090049093161515610160909101529192565b60408051938452602084019290925290820152606001610390565b348015610d5157600080fd5b5060095473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610d7c57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610da757600080fd5b50610417610db6366004614777565b6133ef565b348015610dc757600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610dfb57600080fd5b50610386610e0a366004615048565b61359a565b348015610e1b57600080fd5b50610417610e2a366004614777565b613636565b348015610e3b57600080fd5b50610417610e4a366004614777565b6137e3565b348015610e5b57600080fd5b50610417610e6a366004614821565b613971565b348015610e7b57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610eaf57600080fd5b50610417610ebe366004614777565b6139d1565b348015610ecf57600080fd5b5060075473ffffffffffffffffffffffffffffffffffffffff16610858565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000000009261ffff7601000000000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc69190615072565b0281610fd457610fd461508b565b04905090565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690634d00307090602401602060405180830381865afa15801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e9190615072565b92915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146110cb576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff9092168252600060208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461119e576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600054610100900460ff1615801580611236575060005460ff1615155b80156112525750303b151580611252575060005460ff16600114155b15611289576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156112e757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611356576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff88166113a3576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87166113f0576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff86161561144d57600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88161790555b7f000000000000000000000000000000000000000000000000000000000000000083108061149a57507f000000000000000000000000000000000000000000000000000000000000000083115b156114d1576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000082108061151e57507f000000000000000000000000000000000000000000000000000000000000000082115b15611555576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81831061158e576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008510806115db57507f000000000000000000000000000000000000000000000000000000000000000085115b15611612576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000084108061165f57507f000000000000000000000000000000000000000000000000000000000000000084115b15611696576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008805473ffffffffffffffffffffffffffffffffffffffff808b167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560078054928a16929091169190911790556116f485613c1a565b6008805465ffffffffffff9290921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff90921691909117905561174d84613c1a565b6008805465ffffffffffff929092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790556117a683613c60565b6007805461ffff9290921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff9092169190911790556117fb82613c60565b6007805461ffff92909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff83168117909155604080517f95d89b4100000000000000000000000000000000000000000000000000000000815290516119759373ffffffffffffffffffffffffffffffffffffffff938416931692909217916395d89b41916004808201926000929091908290030181865afa1580156118be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261190491908101906150ba565b6040516020016119149190615128565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f3100000000000000000000000000000000000000000000000000000000000000602083015290613c9e565b61197e88613d6d565b80156119e157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b60006005544614611a6757611a62600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060045490565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003611add576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16611b527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611b9f576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ba881613e26565b611bc381604051806020016040528060008152506000613fda565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611c1d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b6000611ca884338585614132565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003611d1f576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16611d947f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611de1576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dea82613e26565b611df682826001613fda565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611e6b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b600080611f0e8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c918291850190849080828437600092019190915250611f0792508a91508b9050615169565b8787612ccb565b90506005611f1b82612098565b6008811115611f2c57611f2c614bf9565b14611f6b576040517f346e683e000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6000818152600a60205260409081902060010180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085490517f60e69a7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906360e69a7b903490612020908e908e908e908e908e908e908e908e9060040161526f565b6000604051808303818588803b15801561203957600080fd5b505af115801561204d573d6000803e3d6000fd5b50505050507f7b1bcf1ccf901a11589afff5504d59fd0a53780eed2a952adade0348985139e08160405161208391815260200190565b60405180910390a19998505050505050505050565b6000818152600a60209081526040808320815161018081018352815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821696840196909652780100000000000000000000000000000000000000000000000082048116948301949094527c010000000000000000000000000000000000000000000000000000000090048316606082015260019091015480831660808301526401000000008104831660a08301819052680100000000000000008204841660c08401526c010000000000000000000000008204841660e0840152700100000000000000000000000000000000820490931661010083015260ff938104841615156101208301527501000000000000000000000000000000000000000000810484161515610140830152760100000000000000000000000000000000000000000000900490921615156101608301528203612235576040517f219f66a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101200151156122495750600792915050565b8061014001511561225d5750600292915050565b806101600151156122715750600892915050565b8060a0015163ffffffff1642101561228c5750600092915050565b8060c0015163ffffffff164210156122a75750600192915050565b806040015163ffffffff16816060015163ffffffff161115806122de575080610100015163ffffffff16816060015163ffffffff16105b156122ec5750600392915050565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690634d00307090602401602060405180830381865afa15801561235b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237f9190615072565b60000361238f5750600492915050565b6008546040517f6db2feb20000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636db2feb290602401602060405180830381865afa1580156123fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124229190615356565b156124305750600692915050565b50600592915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612490576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008110806124dd57507f000000000000000000000000000000000000000000000000000000000000000081115b15612514576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517401000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527f16569b50c8812bb18e4b5c46b0fee4a9acbb3a9dca1e1badce427e8d75b5652d910160405180910390a16008805465ffffffffffff90921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60006125de83338460405180602001604052806000815250614132565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612636576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600060046126fc83612098565b600881111561270d5761270d614bf9565b14612744576040517f766dfe2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008546040517f7c10dea60000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690637c10dea6906024016020604051808303816000875af11580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190615072565b60408051848152602081018390529192507f65431b33ae1566469324739cd3024c5e8d7422fa2c54e71fda14b92fd5e8f1ea910160405180910390a1919050565b600080612825612d07565b905061282f612d07565b61283c336001420361359a565b11612873576040517fe33f2b3e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855160008190036128b0576040517ffa9039ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855181146128ea576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518114612924576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83516020850120600061293a8989898533612ccb565b6000818152600a60205260409020600181015491925090640100000000900463ffffffff1615612999576040517f60a0c04300000000000000000000000000000000000000000000000000000000815260048101839052602401611f62565b60085474010000000000000000000000000000000000000000810465ffffffffffff9081164201917a01000000000000000000000000000000000000000000000000000090041681016129eb8261442a565b8360010160046101000a81548163ffffffff021916908363ffffffff160217905550612a168161442a565b8360010160086101000a81548163ffffffff021916908363ffffffff160217905550612a418761442a565b83600101600c6101000a81548163ffffffff021916908363ffffffff160217905550612a73612a6e610eee565b61442a565b60018401805463ffffffff92909216700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff90921691909117905582547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178355612af04261442a565b835463ffffffff9190911674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161783556040517f032b260f9afa08d3ff613d6248a8dce651b8c583a050ca2f9c666a179617b15890612b759086908f908f908f908f908c908b90615441565b60405180910390a150919a9950505050505050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612be4576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612c31576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008585858585604051602001612ce69594939291906155c6565b60405160208183030381529060405280519060200120905095945050505050565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000000009261ffff740100000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b600084421115612df5576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612dff6119eb565b73ffffffffffffffffffffffffffffffffffffffff8a1660008181526006602090815260409182902080546001810190915582517f00000000000000000000000000000000000000000000000000000000000000008184015280840194909452606084018d9052608084018c905260a084015260c08084018b90528251808503909101815260e0840190925281519101207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015612f56573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580612fd057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15613007576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613022898b8a60405180602001604052806000815250614132565b9a9950505050505050505050565b600761303b82612098565b600881111561304c5761304c614bf9565b03613083576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff811680835263ffffffff74010000000000000000000000000000000000000000808404821696850196909652780100000000000000000000000000000000000000000000000083048116968401969096527c01000000000000000000000000000000000000000000000000000000009091048516606083015260019092015480851660808301526401000000008104851660a0830152680100000000000000008104851660c08301526c010000000000000000000000008104851660e0830152700100000000000000000000000000000000810490941661010082015260ff9284048316151561012082015275010000000000000000000000000000000000000000008404831615156101408201527601000000000000000000000000000000000000000000009093049091161515610160830152331480159061321357508060e0015163ffffffff1661321082600001516001420361359a565b10155b1561324a576040517f7d78031200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a60205260409081902060010180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000017905560085490517f0dc051f80000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690630dc051f890602401602060405180830381865afa158015613309573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332d9190615356565b156133b7576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b15801561339e57600080fd5b505af11580156133b2573d6000803e3d6000fd5b505050505b6040518281527f88ae8321c96cee88d802409f3677f889d8a6743c4631b069fe600a3a9b07e020906020015b60405180910390a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613446576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081108061349357507f000000000000000000000000000000000000000000000000000000000000000081115b806134be5750600754760100000000000000000000000000000000000000000000900461ffff168110155b156134f5576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600754604080517401000000000000000000000000000000000000000090920461ffff168252602082018390527f3597f3d5106fd545a99b5a9cd1e0e7a985f0477ec13aa8c739119325d747fb35910160405180910390a16007805461ffff90921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6007546040517f3a46b1a800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000921690633a46b1a890604401602060405180830381865afa158015613612573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125de9190615072565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461368d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008110806136da57507f000000000000000000000000000000000000000000000000000000000000000081115b80613703575060075474010000000000000000000000000000000000000000900461ffff168111155b1561373a576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007546040805176010000000000000000000000000000000000000000000090920461ffff168252602082018390527fcefdafdfb2f62f73b0ac8d13e7f3cd4d2dbd9eecd15571b7ac644d97fa9083b1910160405180910390a16007805461ffff909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461383a576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081108061388757507f000000000000000000000000000000000000000000000000000000000000000081115b156138be576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517a01000000000000000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527fffc708f072ca56e3d45ef0cb288b96cb9378f5f63e1646868bfbc9c38f4263a1910160405180910390a16008805465ffffffffffff9092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146139c8576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc38161446a565b60095473ffffffffffffffffffffffffffffffffffffffff163314613a22576040517f16e025ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007613a2d82612098565b6008811115613a3e57613a3e614bf9565b03613a75576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020526040908190206001810180547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000017905560085491517f0dc051f800000000000000000000000000000000000000000000000000000000815260048101849052909173ffffffffffffffffffffffffffffffffffffffff1690630dc051f890602401602060405180830381865afa158015613b36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5a9190615356565b15613be4576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b158015613bcb57600080fd5b505af1158015613bdf573d6000803e3d6000fd5b505050505b6040518281527f0c8bf601915d1f39ef591226bc69b3becc23fcb3616673c419062aa44beb42da906020016133e3565b3b151590565b600065ffffffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b600061ffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff16613cdf576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160208084019190912060025581519082012060035546600555613d66600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6004555050565b600054610100900460ff16613dae576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613e7d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd613ef77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015613f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f8c9190615356565b611bc3576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156140125761400d83614536565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015614097575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261409491810190615072565b60015b6140cd576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114614126576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061400d8383836145ec565b6000600161413f86612098565b600881111561415057614150614bf9565b14614187576040517f8a59eceb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8816845290915290205460ff16156141f1576040517feb20971100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283111561422c576040517f3485325a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff88168452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055878352600a909152812080549091906142bd90879063ffffffff740100000000000000000000000000000000000000009091041661359a565b905084600003614329576142d08161442a565b825463ffffffff78010000000000000000000000000000000000000000000000008083048216909301169091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846001036143935761433a8161442a565b825463ffffffff7c01000000000000000000000000000000000000000000000000000000008083048216909301169091027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846002036143e1576143a48161442a565b6001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000811663ffffffff91821693909301169190911790555b7f0c165c85edbf8f9b99d51793c9429beb9dc2b608a7f81e64623052f829657af3868887848860405161441895949392919061562e565b60405180910390a19695505050505050565b600063ffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179091556001541615611bc357600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b803b614586576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6145f583614617565b6000825111806146025750805b1561400d57614611838361466c565b50505050565b61462081614536565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b6146a6576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516146ce919061567a565b600060405180830381855af49150503d8060008114614709576040519150601f19603f3d011682016040523d82523d6000602084013e61470e565b606091505b509150915061471d8282614726565b95945050505050565b6060821561473557508061106e565b8151156147455781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561478957600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146147b457600080fd5b919050565b600080600080600080600060e0888a0312156147d457600080fd5b6147dd88614790565b96506147eb60208901614790565b95506147f960408901614790565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60006020828403121561483357600080fd5b6125de82614790565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156148b2576148b261483c565b604052919050565b600067ffffffffffffffff8211156148d4576148d461483c565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261491157600080fd5b813561492461491f826148ba565b61486b565b81815284602083860101111561493957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561496b57600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561499057600080fd5b61499c86828701614900565b9150509250925092565b815173ffffffffffffffffffffffffffffffffffffffff168152610180810160208301516149dc602084018263ffffffff169052565b5060408301516149f4604084018263ffffffff169052565b506060830151614a0c606084018263ffffffff169052565b506080830151614a24608084018263ffffffff169052565b5060a0830151614a3c60a084018263ffffffff169052565b5060c0830151614a5460c084018263ffffffff169052565b5060e0830151614a6c60e084018263ffffffff169052565b506101008381015163ffffffff16908301526101208084015115159083015261014080840151151590830152610160928301511515929091019190915290565b60008060408385031215614abf57600080fd5b614ac883614790565b9150602083013567ffffffffffffffff811115614ae457600080fd5b614af085828601614900565b9150509250929050565b60008083601f840112614b0c57600080fd5b50813567ffffffffffffffff811115614b2457600080fd5b6020830191508360208260051b8501011115614b3f57600080fd5b9250929050565b60008060008060008060008060a0898b031215614b6257600080fd5b883567ffffffffffffffff80821115614b7a57600080fd5b614b868c838d01614afa565b909a50985060208b0135915080821115614b9f57600080fd5b614bab8c838d01614afa565b909850965060408b0135915080821115614bc457600080fd5b50614bd18b828c01614afa565b90955093505060608901359150614bea60808a01614790565b90509295985092959890939650565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160098310614c63577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215614c7c57600080fd5b50508035926020909101359150565b600067ffffffffffffffff821115614ca557614ca561483c565b5060051b60200190565b600082601f830112614cc057600080fd5b81356020614cd061491f83614c8b565b82815260059290921b84018101918181019086841115614cef57600080fd5b8286015b84811015614d1157614d0481614790565b8352918301918301614cf3565b509695505050505050565b600082601f830112614d2d57600080fd5b81356020614d3d61491f83614c8b565b82815260059290921b84018101918181019086841115614d5c57600080fd5b8286015b84811015614d115780358352918301918301614d60565b6000614d8561491f84614c8b565b8381529050602080820190600585901b840186811115614da457600080fd5b845b81811015614de057803567ffffffffffffffff811115614dc65760008081fd5b614dd289828901614900565b855250928201928201614da6565b505050509392505050565b600082601f830112614dfc57600080fd5b6125de83833560208501614d77565b60008060008060808587031215614e2157600080fd5b843567ffffffffffffffff80821115614e3957600080fd5b614e4588838901614caf565b95506020870135915080821115614e5b57600080fd5b614e6788838901614d1c565b94506040870135915080821115614e7d57600080fd5b614e8988838901614deb565b93506060870135915080821115614e9f57600080fd5b50614eac87828801614900565b91505092959194509250565b60005b83811015614ed3578181015183820152602001614ebb565b50506000910152565b60008151808452614ef4816020860160208601614eb8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006125de6020830184614edc565b600080600080600060a08688031215614f5157600080fd5b853567ffffffffffffffff80821115614f6957600080fd5b614f7589838a01614caf565b96506020880135915080821115614f8b57600080fd5b614f9789838a01614d1c565b95506040880135915080821115614fad57600080fd5b50614fba88828901614deb565b93505060608601359150614fd060808701614790565b90509295509295909350565b600080600080600080600060e0888a031215614ff757600080fd5b61500088614790565b9650602088013595506040880135945060608801359350608088013560ff8116811461502b57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561505b57600080fd5b61506483614790565b946020939093013593505050565b60006020828403121561508457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000602082840312156150cc57600080fd5b815167ffffffffffffffff8111156150e357600080fd5b8201601f810184136150f457600080fd5b805161510261491f826148ba565b81815285602083850101111561511757600080fd5b61471d826020830160208601614eb8565b6000825161513a818460208701614eb8565b7f20474f5600000000000000000000000000000000000000000000000000000000920191825250600401919050565b60006125de368484614d77565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b81835260006020808501808196508560051b810191508460005b8781101561526257828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe188360301811261521857600080fd5b8701858101903567ffffffffffffffff81111561523457600080fd5b80360382131561524357600080fd5b61524e868284615176565b9a87019a95505050908401906001016151d9565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156152bd5773ffffffffffffffffffffffffffffffffffffffff6152a884614790565b16825260209283019290910190600101615282565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156152f657600080fd5b8860051b9150818a6020830137018281036020908101604085015261531e90820187896151bf565b915050836060830152615349608083018473ffffffffffffffffffffffffffffffffffffffff169052565b9998505050505050505050565b60006020828403121561536857600080fd5b815180151581146125de57600080fd5b600081518084526020808501945080840160005b838110156153be57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161538c565b509495945050505050565b600081518084526020808501945080840160005b838110156153be578151875295820195908201906001016153dd565b600081518084526020808501808196508360051b8101915082860160005b8581101561526257828403895261542f848351614edc565b98850198935090840190600101615417565b600061024089835280602084015261545b8184018a615378565b9050828103604084015261546f81896153c9565b9050828103606084015261548381886153f9565b905082810360808401526154978187614edc565b9150508360a083015282546154da60c0840173ffffffffffffffffffffffffffffffffffffffff831673ffffffffffffffffffffffffffffffffffffffff169052565b63ffffffff60a082901c811660e085015260c082901c811661010085015260e082901c610120850152600185015463ffffffff8282161661014086015291506155316101608501828460201c1663ffffffff169052565b6155496101808501828460401c1663ffffffff169052565b6155616101a08501828460601c1663ffffffff169052565b6155796101c08501828460801c1663ffffffff169052565b5061558f6101e0840160ff8360a01c1615159052565b6155a4610200840160ff8360a81c1615159052565b6155b9610220840160ff8360b01c1615159052565b5098975050505050505050565b60a0815260006155d960a0830188615378565b82810360208401526155eb81886153c9565b905082810360408401526155ff81876153f9565b91505083606083015273ffffffffffffffffffffffffffffffffffffffff831660808301529695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015282606082015260a06080820152600061566f60a0830184614edc565b979650505050505050565b6000825161568c818460208701614eb8565b919091019291505056fea264697066735822122064b51134927b2d8ab75f42bea6c26a1cad09ae79e3446254c7140cc4d5077ab764736f6c634300081000330000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee0

Deployed Bytecode

0x60806040526004361061034a5760003560e01c806379ba5097116101bb578063c82fbd08116100f7578063eb9019d411610095578063f2fde38b1161006f578063f2fde38b14610e4f578063f990b49114610e6f578063fb6f93f914610ea3578063fc0c546a14610ec357600080fd5b8063eb9019d414610def578063ebfdeacf14610e0f578063ef00ef4314610e2f57600080fd5b8063d8bff440116100d1578063d8bff44014610d45578063e30c397814610d70578063e42eb4f614610d9b578063e48083fe14610dbb57600080fd5b8063c82fbd0814610b30578063cbcda20114610b64578063d14b85b914610ba257600080fd5b8063a0a8e46011610164578063b11262631161013e578063b112626314610aa7578063b58131b014610adb578063c3e5178914610af0578063c4d252f514610b1057600080fd5b8063a0a8e46014610a07578063a64e024a14610a53578063aedbfe3314610a8757600080fd5b8063865229731161019557806386522973146109825780638da5cb5b146109b65780639dcbfd7d146109e757600080fd5b806379ba50971461092d5780637c10dea6146109425780637d5e81e21461096257600080fd5b80633bec7f5b1161028a57806352d1902d1161023357806361d585da1161020d57806361d585da1461087d57806363d61a19146108aa57806370ae92d2146108ca57806375a12d721461090d57600080fd5b806352d1902d1461080957806360e69a7b1461081e57806361d027b31461083157600080fd5b8063430694cf11610264578063430694cf146105d557806348b1aeb4146107c55780634f1ef286146107f657600080fd5b80633bec7f5b146105405780633d24375f1461057357806341f9b62c146105b557600080fd5b8063215809ca116102f75780633644e515116102d15780633644e515146104b65780633659cfe6146104cb5780633932abb1146104eb578063395db2cd1461052057600080fd5b8063215809ca1461044d57806323452b9c146104815780632b4656c81461049657600080fd5b8063177e5a9f11610328578063177e5a9f146103e25780631e5cc3bd146104025780631e7b5d3a1461041957600080fd5b806302a251a31461034f578063032bbc53146103995780631703a018146103cd575b600080fd5b34801561035b57600080fd5b506008547a010000000000000000000000000000000000000000000000000000900465ffffffffffff165b6040519081526020015b60405180910390f35b3480156103a557600080fd5b506103867f00000000000000000000000000000000000000000000000000000000000000c881565b3480156103d957600080fd5b50610386610eee565b3480156103ee57600080fd5b506103866103fd366004614777565b610fda565b34801561040e57600080fd5b50610417611074565b005b34801561042557600080fd5b506103867f00000000000000000000000000000000000000000000000000000000000003e881565b34801561045957600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000025881565b34801561048d57600080fd5b50610417611147565b3480156104a257600080fd5b506104176104b13660046147b9565b611219565b3480156104c257600080fd5b506103866119eb565b3480156104d757600080fd5b506104176104e6366004614821565b611a6e565b3480156104f757600080fd5b5060085474010000000000000000000000000000000000000000900465ffffffffffff16610386565b34801561052c57600080fd5b5061041761053b366004614821565b611bc6565b34801561054c57600080fd5b50600754760100000000000000000000000000000000000000000000900461ffff16610386565b34801561057f57600080fd5b5061038661058e366004614777565b6000908152600a602052604090206001015468010000000000000000900463ffffffff1690565b3480156105c157600080fd5b506103866105d0366004614956565b611c9a565b3480156105e157600080fd5b506107b86105f0366004614777565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152506000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821695840195909552780100000000000000000000000000000000000000000000000082048116958301959095527c010000000000000000000000000000000000000000000000000000000090048416606082015260019091015480841660808301526401000000008104841660a0830152680100000000000000008104841660c08301526c010000000000000000000000008104841660e0830152700100000000000000000000000000000000810490931661010082015260ff91830482161515610120820152750100000000000000000000000000000000000000000083048216151561014082015276010000000000000000000000000000000000000000000090920416151561016082015290565b60405161039091906149a6565b3480156107d157600080fd5b5060075474010000000000000000000000000000000000000000900461ffff16610386565b610417610804366004614aac565b611cb0565b34801561081557600080fd5b50610386611dfa565b61038661082c366004614b46565b611e90565b34801561083d57600080fd5b5060085473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610390565b34801561088957600080fd5b5061089d610898366004614777565b612098565b6040516103909190614c28565b3480156108b657600080fd5b506104176108c5366004614777565b612439565b3480156108d657600080fd5b506103866108e5366004614821565b73ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205490565b34801561091957600080fd5b50610386610928366004614c69565b6125c1565b34801561093957600080fd5b506104176125e5565b34801561094e57600080fd5b5061038661095d366004614777565b6126ef565b34801561096e57600080fd5b5061038661097d366004614e0b565b61281a565b34801561098e57600080fd5b506103867f4b87515bde17bd1a40e570a7c028fa4b7e66dd1ed9dc7c0cd8fd78d67ca34f2881565b3480156109c257600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610858565b3480156109f357600080fd5b50610417610a02366004614821565b612b8d565b348015610a1357600080fd5b50604080518082018252600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015290516103909190614f26565b348015610a5f57600080fd5b506103867f0000000000000000000000000000000000000000000000000000000000dd7c0081565b348015610a9357600080fd5b50610386610aa2366004614f39565b612ccb565b348015610ab357600080fd5b506103867f0000000000000000000000000000000000000000000000000000000000dd7c0081565b348015610ae757600080fd5b50610386612d07565b348015610afc57600080fd5b50610386610b0b366004614fdc565b612db9565b348015610b1c57600080fd5b50610417610b2b366004614777565b613030565b348015610b3c57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000181565b348015610b7057600080fd5b50610386610b7f366004614777565b6000908152600a6020526040902060010154640100000000900463ffffffff1690565b348015610bae57600080fd5b50610d2a610bbd366004614777565b6000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff740100000000000000000000000000000000000000008083048216958401959095527801000000000000000000000000000000000000000000000000820481169583018690527c0100000000000000000000000000000000000000000000000000000000909104811660608301819052600190930154808216608084018190526401000000008204831660a0850152680100000000000000008204831660c08501526c010000000000000000000000008204831660e0850152700100000000000000000000000000000000820490921661010084015260ff94810485161515610120840152750100000000000000000000000000000000000000000081048516151561014084015276010000000000000000000000000000000000000000000090049093161515610160909101529192565b60408051938452602084019290925290820152606001610390565b348015610d5157600080fd5b5060095473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610d7c57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610da757600080fd5b50610417610db6366004614777565b6133ef565b348015610dc757600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000181565b348015610dfb57600080fd5b50610386610e0a366004615048565b61359a565b348015610e1b57600080fd5b50610417610e2a366004614777565b613636565b348015610e3b57600080fd5b50610417610e4a366004614777565b6137e3565b348015610e5b57600080fd5b50610417610e6a366004614821565b613971565b348015610e7b57600080fd5b506103867f00000000000000000000000000000000000000000000000000000000000007d081565b348015610eaf57600080fd5b50610417610ebe366004614777565b6139d1565b348015610ecf57600080fd5b5060075473ffffffffffffffffffffffffffffffffffffffff16610858565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000027109261ffff7601000000000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc69190615072565b0281610fd457610fd461508b565b04905090565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690634d00307090602401602060405180830381865afa15801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e9190615072565b92915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146110cb576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff9092168252600060208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461119e576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600054610100900460ff1615801580611236575060005460ff1615155b80156112525750303b151580611252575060005460ff16600114155b15611289576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156112e757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee01614611356576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff88166113a3576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87166113f0576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff86161561144d57600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88161790555b7f000000000000000000000000000000000000000000000000000000000000000183108061149a57507f00000000000000000000000000000000000000000000000000000000000003e883115b156114d1576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000c882108061151e57507f00000000000000000000000000000000000000000000000000000000000007d082115b15611555576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81831061158e576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000018510806115db57507f0000000000000000000000000000000000000000000000000000000000dd7c0085115b15611612576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000025884108061165f57507f0000000000000000000000000000000000000000000000000000000000dd7c0084115b15611696576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008805473ffffffffffffffffffffffffffffffffffffffff808b167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560078054928a16929091169190911790556116f485613c1a565b6008805465ffffffffffff9290921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff90921691909117905561174d84613c1a565b6008805465ffffffffffff929092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790556117a683613c60565b6007805461ffff9290921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff9092169190911790556117fb82613c60565b6007805461ffff92909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff83168117909155604080517f95d89b4100000000000000000000000000000000000000000000000000000000815290516119759373ffffffffffffffffffffffffffffffffffffffff938416931692909217916395d89b41916004808201926000929091908290030181865afa1580156118be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261190491908101906150ba565b6040516020016119149190615128565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f3100000000000000000000000000000000000000000000000000000000000000602083015290613c9e565b61197e88613d6d565b80156119e157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b60006005544614611a6757611a62600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060045490565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006763c3210bdc1d9a1f917706a16f259913198376163003611add576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000006763c3210bdc1d9a1f917706a16f25991319837673ffffffffffffffffffffffffffffffffffffffff16611b527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611b9f576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ba881613e26565b611bc381604051806020016040528060008152506000613fda565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611c1d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b6000611ca884338585614132565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006763c3210bdc1d9a1f917706a16f259913198376163003611d1f576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000006763c3210bdc1d9a1f917706a16f25991319837673ffffffffffffffffffffffffffffffffffffffff16611d947f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611de1576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dea82613e26565b611df682826001613fda565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006763c3210bdc1d9a1f917706a16f2599131983761614611e6b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b600080611f0e8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c918291850190849080828437600092019190915250611f0792508a91508b9050615169565b8787612ccb565b90506005611f1b82612098565b6008811115611f2c57611f2c614bf9565b14611f6b576040517f346e683e000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6000818152600a60205260409081902060010180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085490517f60e69a7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906360e69a7b903490612020908e908e908e908e908e908e908e908e9060040161526f565b6000604051808303818588803b15801561203957600080fd5b505af115801561204d573d6000803e3d6000fd5b50505050507f7b1bcf1ccf901a11589afff5504d59fd0a53780eed2a952adade0348985139e08160405161208391815260200190565b60405180910390a19998505050505050505050565b6000818152600a60209081526040808320815161018081018352815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821696840196909652780100000000000000000000000000000000000000000000000082048116948301949094527c010000000000000000000000000000000000000000000000000000000090048316606082015260019091015480831660808301526401000000008104831660a08301819052680100000000000000008204841660c08401526c010000000000000000000000008204841660e0840152700100000000000000000000000000000000820490931661010083015260ff938104841615156101208301527501000000000000000000000000000000000000000000810484161515610140830152760100000000000000000000000000000000000000000000900490921615156101608301528203612235576040517f219f66a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101200151156122495750600792915050565b8061014001511561225d5750600292915050565b806101600151156122715750600892915050565b8060a0015163ffffffff1642101561228c5750600092915050565b8060c0015163ffffffff164210156122a75750600192915050565b806040015163ffffffff16816060015163ffffffff161115806122de575080610100015163ffffffff16816060015163ffffffff16105b156122ec5750600392915050565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690634d00307090602401602060405180830381865afa15801561235b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237f9190615072565b60000361238f5750600492915050565b6008546040517f6db2feb20000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636db2feb290602401602060405180830381865afa1580156123fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124229190615356565b156124305750600692915050565b50600592915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612490576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000018110806124dd57507f0000000000000000000000000000000000000000000000000000000000dd7c0081115b15612514576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517401000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527f16569b50c8812bb18e4b5c46b0fee4a9acbb3a9dca1e1badce427e8d75b5652d910160405180910390a16008805465ffffffffffff90921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60006125de83338460405180602001604052806000815250614132565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612636576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600060046126fc83612098565b600881111561270d5761270d614bf9565b14612744576040517f766dfe2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008546040517f7c10dea60000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690637c10dea6906024016020604051808303816000875af11580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190615072565b60408051848152602081018390529192507f65431b33ae1566469324739cd3024c5e8d7422fa2c54e71fda14b92fd5e8f1ea910160405180910390a1919050565b600080612825612d07565b905061282f612d07565b61283c336001420361359a565b11612873576040517fe33f2b3e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855160008190036128b0576040517ffa9039ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855181146128ea576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518114612924576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83516020850120600061293a8989898533612ccb565b6000818152600a60205260409020600181015491925090640100000000900463ffffffff1615612999576040517f60a0c04300000000000000000000000000000000000000000000000000000000815260048101839052602401611f62565b60085474010000000000000000000000000000000000000000810465ffffffffffff9081164201917a01000000000000000000000000000000000000000000000000000090041681016129eb8261442a565b8360010160046101000a81548163ffffffff021916908363ffffffff160217905550612a168161442a565b8360010160086101000a81548163ffffffff021916908363ffffffff160217905550612a418761442a565b83600101600c6101000a81548163ffffffff021916908363ffffffff160217905550612a73612a6e610eee565b61442a565b60018401805463ffffffff92909216700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff90921691909117905582547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178355612af04261442a565b835463ffffffff9190911674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161783556040517f032b260f9afa08d3ff613d6248a8dce651b8c583a050ca2f9c666a179617b15890612b759086908f908f908f908f908c908b90615441565b60405180910390a150919a9950505050505050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612be4576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612c31576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008585858585604051602001612ce69594939291906155c6565b60405160208183030381529060405280519060200120905095945050505050565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000027109261ffff740100000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b600084421115612df5576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612dff6119eb565b73ffffffffffffffffffffffffffffffffffffffff8a1660008181526006602090815260409182902080546001810190915582517f4b87515bde17bd1a40e570a7c028fa4b7e66dd1ed9dc7c0cd8fd78d67ca34f288184015280840194909452606084018d9052608084018c905260a084015260c08084018b90528251808503909101815260e0840190925281519101207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015612f56573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580612fd057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15613007576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613022898b8a60405180602001604052806000815250614132565b9a9950505050505050505050565b600761303b82612098565b600881111561304c5761304c614bf9565b03613083576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff811680835263ffffffff74010000000000000000000000000000000000000000808404821696850196909652780100000000000000000000000000000000000000000000000083048116968401969096527c01000000000000000000000000000000000000000000000000000000009091048516606083015260019092015480851660808301526401000000008104851660a0830152680100000000000000008104851660c08301526c010000000000000000000000008104851660e0830152700100000000000000000000000000000000810490941661010082015260ff9284048316151561012082015275010000000000000000000000000000000000000000008404831615156101408201527601000000000000000000000000000000000000000000009093049091161515610160830152331480159061321357508060e0015163ffffffff1661321082600001516001420361359a565b10155b1561324a576040517f7d78031200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a60205260409081902060010180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000017905560085490517f0dc051f80000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690630dc051f890602401602060405180830381865afa158015613309573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332d9190615356565b156133b7576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b15801561339e57600080fd5b505af11580156133b2573d6000803e3d6000fd5b505050505b6040518281527f88ae8321c96cee88d802409f3677f889d8a6743c4631b069fe600a3a9b07e020906020015b60405180910390a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613446576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000181108061349357507f00000000000000000000000000000000000000000000000000000000000003e881115b806134be5750600754760100000000000000000000000000000000000000000000900461ffff168110155b156134f5576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600754604080517401000000000000000000000000000000000000000090920461ffff168252602082018390527f3597f3d5106fd545a99b5a9cd1e0e7a985f0477ec13aa8c739119325d747fb35910160405180910390a16007805461ffff90921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6007546040517f3a46b1a800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000921690633a46b1a890604401602060405180830381865afa158015613612573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125de9190615072565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461368d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000c88110806136da57507f00000000000000000000000000000000000000000000000000000000000007d081115b80613703575060075474010000000000000000000000000000000000000000900461ffff168111155b1561373a576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007546040805176010000000000000000000000000000000000000000000090920461ffff168252602082018390527fcefdafdfb2f62f73b0ac8d13e7f3cd4d2dbd9eecd15571b7ac644d97fa9083b1910160405180910390a16007805461ffff909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461383a576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000025881108061388757507f0000000000000000000000000000000000000000000000000000000000dd7c0081115b156138be576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517a01000000000000000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527fffc708f072ca56e3d45ef0cb288b96cb9378f5f63e1646868bfbc9c38f4263a1910160405180910390a16008805465ffffffffffff9092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146139c8576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc38161446a565b60095473ffffffffffffffffffffffffffffffffffffffff163314613a22576040517f16e025ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007613a2d82612098565b6008811115613a3e57613a3e614bf9565b03613a75576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020526040908190206001810180547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000017905560085491517f0dc051f800000000000000000000000000000000000000000000000000000000815260048101849052909173ffffffffffffffffffffffffffffffffffffffff1690630dc051f890602401602060405180830381865afa158015613b36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5a9190615356565b15613be4576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b158015613bcb57600080fd5b505af1158015613bdf573d6000803e3d6000fd5b505050505b6040518281527f0c8bf601915d1f39ef591226bc69b3becc23fcb3616673c419062aa44beb42da906020016133e3565b3b151590565b600065ffffffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b600061ffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff16613cdf576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160208084019190912060025581519082012060035546600555613d66600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6004555050565b600054610100900460ff16613dae576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613e7d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee073ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd613ef77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015613f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f8c9190615356565b611bc3576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156140125761400d83614536565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015614097575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261409491810190615072565b60015b6140cd576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114614126576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061400d8383836145ec565b6000600161413f86612098565b600881111561415057614150614bf9565b14614187576040517f8a59eceb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8816845290915290205460ff16156141f1576040517feb20971100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283111561422c576040517f3485325a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff88168452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055878352600a909152812080549091906142bd90879063ffffffff740100000000000000000000000000000000000000009091041661359a565b905084600003614329576142d08161442a565b825463ffffffff78010000000000000000000000000000000000000000000000008083048216909301169091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846001036143935761433a8161442a565b825463ffffffff7c01000000000000000000000000000000000000000000000000000000008083048216909301169091027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846002036143e1576143a48161442a565b6001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000811663ffffffff91821693909301169190911790555b7f0c165c85edbf8f9b99d51793c9429beb9dc2b608a7f81e64623052f829657af3868887848860405161441895949392919061562e565b60405180910390a19695505050505050565b600063ffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179091556001541615611bc357600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b803b614586576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6145f583614617565b6000825111806146025750805b1561400d57614611838361466c565b50505050565b61462081614536565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b6146a6576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516146ce919061567a565b600060405180830381855af49150503d8060008114614709576040519150601f19603f3d011682016040523d82523d6000602084013e61470e565b606091505b509150915061471d8282614726565b95945050505050565b6060821561473557508061106e565b8151156147455781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561478957600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146147b457600080fd5b919050565b600080600080600080600060e0888a0312156147d457600080fd5b6147dd88614790565b96506147eb60208901614790565b95506147f960408901614790565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60006020828403121561483357600080fd5b6125de82614790565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156148b2576148b261483c565b604052919050565b600067ffffffffffffffff8211156148d4576148d461483c565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261491157600080fd5b813561492461491f826148ba565b61486b565b81815284602083860101111561493957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561496b57600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561499057600080fd5b61499c86828701614900565b9150509250925092565b815173ffffffffffffffffffffffffffffffffffffffff168152610180810160208301516149dc602084018263ffffffff169052565b5060408301516149f4604084018263ffffffff169052565b506060830151614a0c606084018263ffffffff169052565b506080830151614a24608084018263ffffffff169052565b5060a0830151614a3c60a084018263ffffffff169052565b5060c0830151614a5460c084018263ffffffff169052565b5060e0830151614a6c60e084018263ffffffff169052565b506101008381015163ffffffff16908301526101208084015115159083015261014080840151151590830152610160928301511515929091019190915290565b60008060408385031215614abf57600080fd5b614ac883614790565b9150602083013567ffffffffffffffff811115614ae457600080fd5b614af085828601614900565b9150509250929050565b60008083601f840112614b0c57600080fd5b50813567ffffffffffffffff811115614b2457600080fd5b6020830191508360208260051b8501011115614b3f57600080fd5b9250929050565b60008060008060008060008060a0898b031215614b6257600080fd5b883567ffffffffffffffff80821115614b7a57600080fd5b614b868c838d01614afa565b909a50985060208b0135915080821115614b9f57600080fd5b614bab8c838d01614afa565b909850965060408b0135915080821115614bc457600080fd5b50614bd18b828c01614afa565b90955093505060608901359150614bea60808a01614790565b90509295985092959890939650565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160098310614c63577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215614c7c57600080fd5b50508035926020909101359150565b600067ffffffffffffffff821115614ca557614ca561483c565b5060051b60200190565b600082601f830112614cc057600080fd5b81356020614cd061491f83614c8b565b82815260059290921b84018101918181019086841115614cef57600080fd5b8286015b84811015614d1157614d0481614790565b8352918301918301614cf3565b509695505050505050565b600082601f830112614d2d57600080fd5b81356020614d3d61491f83614c8b565b82815260059290921b84018101918181019086841115614d5c57600080fd5b8286015b84811015614d115780358352918301918301614d60565b6000614d8561491f84614c8b565b8381529050602080820190600585901b840186811115614da457600080fd5b845b81811015614de057803567ffffffffffffffff811115614dc65760008081fd5b614dd289828901614900565b855250928201928201614da6565b505050509392505050565b600082601f830112614dfc57600080fd5b6125de83833560208501614d77565b60008060008060808587031215614e2157600080fd5b843567ffffffffffffffff80821115614e3957600080fd5b614e4588838901614caf565b95506020870135915080821115614e5b57600080fd5b614e6788838901614d1c565b94506040870135915080821115614e7d57600080fd5b614e8988838901614deb565b93506060870135915080821115614e9f57600080fd5b50614eac87828801614900565b91505092959194509250565b60005b83811015614ed3578181015183820152602001614ebb565b50506000910152565b60008151808452614ef4816020860160208601614eb8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006125de6020830184614edc565b600080600080600060a08688031215614f5157600080fd5b853567ffffffffffffffff80821115614f6957600080fd5b614f7589838a01614caf565b96506020880135915080821115614f8b57600080fd5b614f9789838a01614d1c565b95506040880135915080821115614fad57600080fd5b50614fba88828901614deb565b93505060608601359150614fd060808701614790565b90509295509295909350565b600080600080600080600060e0888a031215614ff757600080fd5b61500088614790565b9650602088013595506040880135945060608801359350608088013560ff8116811461502b57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561505b57600080fd5b61506483614790565b946020939093013593505050565b60006020828403121561508457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000602082840312156150cc57600080fd5b815167ffffffffffffffff8111156150e357600080fd5b8201601f810184136150f457600080fd5b805161510261491f826148ba565b81815285602083850101111561511757600080fd5b61471d826020830160208601614eb8565b6000825161513a818460208701614eb8565b7f20474f5600000000000000000000000000000000000000000000000000000000920191825250600401919050565b60006125de368484614d77565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b81835260006020808501808196508560051b810191508460005b8781101561526257828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe188360301811261521857600080fd5b8701858101903567ffffffffffffffff81111561523457600080fd5b80360382131561524357600080fd5b61524e868284615176565b9a87019a95505050908401906001016151d9565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156152bd5773ffffffffffffffffffffffffffffffffffffffff6152a884614790565b16825260209283019290910190600101615282565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156152f657600080fd5b8860051b9150818a6020830137018281036020908101604085015261531e90820187896151bf565b915050836060830152615349608083018473ffffffffffffffffffffffffffffffffffffffff169052565b9998505050505050505050565b60006020828403121561536857600080fd5b815180151581146125de57600080fd5b600081518084526020808501945080840160005b838110156153be57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161538c565b509495945050505050565b600081518084526020808501945080840160005b838110156153be578151875295820195908201906001016153dd565b600081518084526020808501808196508360051b8101915082860160005b8581101561526257828403895261542f848351614edc565b98850198935090840190600101615417565b600061024089835280602084015261545b8184018a615378565b9050828103604084015261546f81896153c9565b9050828103606084015261548381886153f9565b905082810360808401526154978187614edc565b9150508360a083015282546154da60c0840173ffffffffffffffffffffffffffffffffffffffff831673ffffffffffffffffffffffffffffffffffffffff169052565b63ffffffff60a082901c811660e085015260c082901c811661010085015260e082901c610120850152600185015463ffffffff8282161661014086015291506155316101608501828460201c1663ffffffff169052565b6155496101808501828460401c1663ffffffff169052565b6155616101a08501828460601c1663ffffffff169052565b6155796101c08501828460801c1663ffffffff169052565b5061558f6101e0840160ff8360a01c1615159052565b6155a4610200840160ff8360a81c1615159052565b6155b9610220840160ff8360b01c1615159052565b5098975050505050505050565b60a0815260006155d960a0830188615378565b82810360208401526155eb81886153c9565b905082810360408401526155ff81876153f9565b91505083606083015273ffffffffffffffffffffffffffffffffffffffff831660808301529695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015282606082015260a06080820152600061566f60a0830184614edc565b979650505050505050565b6000825161568c818460208701614eb8565b919091019291505056fea264697066735822122064b51134927b2d8ab75f42bea6c26a1cad09ae79e3446254c7140cc4d5077ab764736f6c63430008100033

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

0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee0

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

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee0


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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