/*
~~~^~~~~!!!77!!!!!!77!!!!!!!!!!!!!!!!!!~~~~^^^:::::::::::::::::::^^^^^^:::::.::^^^~~!!!777777??7!!!~
^^^::::::^^^^~~~~~~!!!!!!!!!!!!!!!!!!!~~~^^:::::::::::::::::::::^^^^^^^^::::::^~~~~~!!7777777!!~~^^^
^^^::::::.....::^^^^^^^~~~~~!!!!!!!!!~~~^::.  ...::::::::::::::::::^^^^^:::::::^~~^~~!!!!!!~~^^:::^^
::::::::::......:::::::^^^^~~~~~~~~~~~~~^^::::::::^^^^^:::::...::::::::::::::::^^^^^^^^^::::::::::^^
^::::::::::::....:::::::::^^^~!!7??JJYYYYYY55555YYYYYYYYYYJ??7!~^::.......::::::::::...:::::::::^^~~
^^^^^^^^^^^^^^:::::::^^^~!7JY55PPPPPPPPPPPPPPP5555555555555PPP555YJ?!~^:...:::::::::::::::::::^~~!!!
~~~~~~~~~~~~~~~~~~~~~~!J5PPPPPPPPGGGGGGPPPPPPPPPP555555555555555555PP55Y?7~^:::::::::::::::^~!!7!777
^~^^~~~^^~~~~~~~~~~~7JPPGGGPPPPPPPPPPPPPPPPP5555555555555555555555555555PP55YJ7~::::::^^~~~!!!!!!!!!
~~^^^^~^^^^^^^^^^~?5GGGGGGPPPPPPPPP5555555YYYY55555555YYY55555YYYYYYY55555555555Y7~:::^~~~!!~~~^^^^^
~~~~^^^^^^^^^^^!JPGGPPPPPP55555555YYYYYYYYYYYYYYYYYYYYYYYYYYY55YYYYYYYYYYYYYYYYYY55Y?!^^^~~^^^^^^^^:
~~~~~~~~~~^^~7YPPPPP5555555555YYYYYYYYYYYYJJJJ??JYYYYYYYYYYJ7J555YYJJJJ?JJJYYYYJJYYYY5Y?~^^^:^^^^^^^
~~~~~~~~~~~~?5P55555555555YYYYYYYYYJJJJJJJJJ??YYYY5YYYYYYYJJ7!?555YJJJJ??J?JJY55JJJYYYY5Y!::^^^^^^~~
~~~~~~~~~~~?5555555YY55YYYJYYYYYYJJJJJJJJJ??JY5YY5YYYYY5YYYJ7!!?55YJJJ?J??J?JJY5YJJJY5YYYY~^^^^~~~~!
~~~~~~~~~~?5555555YYY5Y??JY555YJJJJJJJJJJ??Y55YYYYYYYYY555YJ?!!!Y5YJJJ?J??J?JJJY5YJJJYYYYYJ~~~!!!!!!
~~~~~~~~~~Y55555YJJY5Y?7JYY555JJJJJJJJJYJ7J55YJYYYYYYY5555YY77!!?5YJJJ????J??JJJYYJJJJ5YJY5?!!!!!!!!
~~~~~~~~^?5555YJ?77Y5J7?JYY55YJJJJJJJJJJ??Y5YJYYJJYYYY5555YJ!777?YYJJJ?J?????JJJJJYJJJ5YYY5Y~~~~~!!!
~~~~~~~~~Y555YJ?!!755J?JYYY55YJJJJJJJJJJ7J55JJYY??YYYY5555Y?!!???YYJJ?5#&#G5J?JJJJJJJJ5YYY55!~~~~!!!
~~~~~~~~7555YJJ7!!J55J?Y5YY55YJJJJJJJYJ??YYYJ5GGGBBPYYYY55J?!!???JJJJ?JYPB&@@#GPYJJJJYYYYY5Y!!!!!!!!
!~~~~~~~J55YJ?7!!7555JJY5YJ55YYJJJJJJYJ7JPB&&@&&BG5?77!!!7!7~~!!~~~~~~~~~~!?YPB&&P?JJYYYYY5?~~~~~~!~
~~~~~~~~Y55J?7!!!J555JJ55YJY55YJJJJJJJ?5&@BYJ7!~^^^^^^^^^^^^^^^^^^^^^^^^^^::::^~Y&B77JJYYYJ~~~~~~~~~
~~~^^^^^J5YJ7!!!7Y555YY55YJJ555YJJJJYP&&5!^::^^^^^^^^^^^^^^^^^^^^^^^^^^^^!7?JJ?7~!P7^~?J?7~~~~~~~~~~
^^^^^^:^JYJJ7!!!755555555Y??5P5YJJJP&#Y~:^^^^^:::::^^^^^^^^^^^^^^^^^^^^75G#&&&&&B!^^^^~!~~~~~~~~~~~~
:::::::!5YJ?!!!!J5555555YJJ77??JYJG#J^:^:^^~!7??JJJ7^^^^^^^^^^^^^^^^^^^7GB77BGG&&P~^^^^^^^^^^^^^^^^^
::....~5YJJ?!!!7555555YYJJJ7~^^^~!?~:^^~?YPPGPP5J?7!^^^^^^^^^^^^^^^~^^!#@P  ?@&@B&G~~~^:::::::::::::
::...:YYJJJ7!!7Y5555YYYYY?!~^^^^^^^^^^^JGBBGB5P@&#P?^^^^^^^^^^^^^^~~^^P@BY5YB&@@GB5?^^!~^^:^^^^^^^!!
.....75YJJJ7!7Y55YYJJJ?77!~^^^^^^^^^^!P#@&Y!J&#&@@@@P~^^^^^^^^^^^~~~^~&GG#@B5&@&PP.~~^YPYJ7!~~~!?YGG
....:55JJJJ7!J5J?77!~~~^^^^^^^^^^^^^Y&@GBBG&PG&&@@@@@Y:^^^^^^^^^^~~~~~BG5&@@&@@PB?:~^~PBBBBGGGGGBBBB
..:~?5YJJJ?~~~~~~^^^^^^^^^^^^^^^^^^?#?BBJB&&&&&@@@@G#G^^^^^^^^^^^~~~~^Y#Y5#&&&JGG^~~^!BBBBBBBBBBBBBB
.^?5P5YJJ7~~~~^^^^^^^^^^^^^^^^^^^^^77 ?&5JB&@&&@@##PBB~^^^~^^^^^^~~~~~~YPPPP5PGP~^~~^JBBBBBBBBBBBBBB
7YPGP5YJJ7~~~~~^^^^^^^^^^^^^^^^^^^^^^:.Y&PYPB###B~^#&Y^^^^^~~~^^~~~~~~~^~!?Y5GB?^~~^~GBBBBBBBBBBBBBB
PGGGP5YJY?77~~~~~^^^^^^^^^^^^^^^^^^^^^:.!PBG55YY5PP&Y^^^~^^^~^^^^^~~~~~~~~~~~!77~~^^JBBBBBBBBBBBBBBB
GGGGGPYJJ?Y5Y7!~~~~~^^^^^^^^^^^^^^^^^^^^::~7YGBGGG5!^^^^^^^^^^^^:::^~~~~~~~~~~~~~~^7BBBBBBBBBBBBBBBB
GPGGGPYJJ?Y555PY?!~~~^~~~~~~^^^~~^^^^^^^^^^^!??7!~^^^^^^^^^^^^^^^:^^^^~~~~~~~~~~~^7PBBBBBBBBBBGBBBBB
PGGGGGPYJJY5555PPPP5J?!~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~^~~~~~~~^~?5GGBBBBGGGGGGBBBBB
PGGGGGGPYJ555555555PPGGP5J?7!~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^~~~!!7!~^~~~~~~~7Y55GGGGGGGBBBGBBGBBB
PGGGGGGGPYY55555555555PPGGGGP5YJ7!~~~~~^^^^^^^^^^^^^^^^^^^^^^^~~~~~~^^~~~~~~~7Y555PGGGGGGBBBBBBBBBBB
GGGGGGPPPPP555555555555PPPPGGGGGGGP5Y?7!~^^^^^^^^^^^^^^^^^^^^~^^^^^^^~~~~~!J555555PGGBGGGGGGBBBBBBBB
GPGPPPPPPGGGGP55555555555PPPPPGGGGGGGGGP5Y?!~^^^^^^^^^^^^^^~~~^^^^^^~~!?JY55555555PGGGGGGGGGGGGGGGGG
GPGGPPPPPPPGGGPPP5555555555PPPPPPGGGGGGGGGGGP5J?7!~~~^^^^~~~~~~~!!7?J5555555555555PGGGGGGGGGGGGGGGGG
GGGGGGGGGPGGPPGGGPP5555555555PPPPPGGGGGGGGGPPGPGGY777!!!!~~~~~~?P5PPP5555555555555PGGGGGGGGGGPPGPPPG
GGPGGGGGGGGGPPPPPGGPP5555555555PPPPGGGGGPP5Y5PPGGY777777!!!!!!~?PPP5555PPPPP5555PPPGGGGGGGGGGGPGPPPP
PPPPPPPPPPPPPPGPPPGGPPP555555555PPPPP5J?7!!!~!J5J7!!!77!!!!!!!~!JJ!!!!!7?JYPGGGPPGGGGGGPGGPGGGPPGPPP
55PPPPPPPGPGGGGPPPGGPPP5PPPPP55PGPJ!!~~~~~~!!~~JYYJ?7!!!!!~!!7JYJ~~~!~~~~~~!7YPPGGGGGGGGPPPGGGPPP555
5555PPPGGGGGPPP5PPGGPPPPPPPPP5PP57~~~~~~~~~!!~~7??JYYYJ???JJYYJ?~~~!~~~~!!!!~~!YGGPPPPGGGGGGPP55YYYY
5555555PP55YYYYYPPPPPGG55PPPPPPY!~~!~~~~~~~~!!~!??777??JJJ??777!~~!!~~~~!!!!!~~~JP5555PPPPPPP5YYYYY5
55YY55555Y5YYYY5555PGGGPPPPPP5Y!~~~!!~~~~~~~!!~~7J7777!!!!777?7~~~!~~~~!!!!!!!!!!YP5Y5PPPPPP555YY55P
5555555555P5PPP55PPPPGPPPPPPP57~~~~~~~~~~~~~~!!~~??777777777??!~~~~~~~~!!!!!!!!!~75P55PPPPPPPPP5555P
555P55555P5PPPPPPPPPPPPYYYYPPY!!!!~~~~~~~~~~!!!~~!?7!!777777?!~!7!!!!!!!!!!!~!!!!~JGGPPPPGGPPPPPPPP5
PPP55PP555PPPPPPPPP55YYYYJY5Y?!!!!~~~!?7???????7~~7!~!??J?~~!~!????????????7~!!!!~!PGPPGGGGGPPPGPP55
PPPPPGPPPPPPGGGGPP5YYYYYYJYJJ!!!!~~~~????JJJ????~~777YYYJJJ7~~7JJJJ??JJJJJJ!~!!!!!~JP55PGBBGGGGGPP5P
GGGGGPJ?77??JY5GPPP555YJJJJJ7!!!!~~~!??????????J!~!??77!77!7~~7JJJJJJJ?JJJJ7~~!!!!~?GPPPGGBBGGBGGPPP
*/

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol


// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

// SPDX-License-Identifier: MIT

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol
/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

// File: dao.sol





pragma solidity ^0.8.0;


contract TheDAO {
    struct Proposal {
        address proposer;
        uint256 endTime;
        string description;
        uint256 voteCount;
        bool executed;
    }

    mapping(uint256 => Proposal) public proposals;
    uint256 public proposalCount;
    IERC721 public nftContract;
    address public admin;
    uint256 public votingPeriod;

    struct Ticker {
        string name;
        uint256 multiplier;
    }

    mapping(address => Ticker) public tickerMultipliers;

    event ProposalCreated(address indexed proposer, uint256 proposalId);

    constructor() {
        admin = msg.sender;
        tickerMultipliers[address(0)] = Ticker("milady", 10);
    }

    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;
    }

    function setNFTContract(address _nftContract) external onlyAdmin {
        nftContract = IERC721(_nftContract);
    }

    function setVotingPeriod(uint256 _votingPeriod) external onlyAdmin {
        votingPeriod = _votingPeriod;
    }

    function setMultiplier(address _nftHolder, string memory _name, uint256 _multiplier) external onlyAdmin {
        tickerMultipliers[_nftHolder] = Ticker(_name, _multiplier);
    }

    function createProposal(string calldata _description) external {
        require(address(nftContract) != address(0), "NFT contract not set");
        require(votingPeriod > 0, "Voting period not set");

        proposalCount += 1;
        proposals[proposalCount] = Proposal(
            msg.sender,
            block.timestamp + votingPeriod,
            _description,
            0,
            false
        );
        emit ProposalCreated(msg.sender, proposalCount);
    }

    function vote(uint256 proposalId) external {
        require(address(nftContract) != address(0), "NFT contract not set");

        Proposal storage proposal = proposals[proposalId];
        require(proposal.endTime > block.timestamp, "Voting period over");
        require(nftContract.ownerOf(uint256(uint160(msg.sender))) == msg.sender, "Must hold NFT to vote");

        Ticker memory voterTicker = tickerMultipliers[msg.sender];
        uint256 votePower = voterTicker.multiplier;
        proposal.voteCount += votePower;
    }

    function execute(uint256 proposalId, uint256 quorum) external {
        require(votingPeriod > 0, "Voting period not set");

        Proposal storage proposal = proposals[proposalId];
        require(proposal.endTime <= block.timestamp, "Voting period ongoing");
        require(proposal.proposer != address(0), "Already executed");
        require(proposal.voteCount >= quorum, "Not enough votes");

        // Execute proposal
        // Implement custom logic based on proposal
        proposal.executed = true;
    }

    function setAdmin(address _admin) external onlyAdmin {
        admin = _admin;
    }
}