//SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;




/*

Open source Dutch Auction contract

Dutch Auction that exposes a function to minters that allows them to pull difference between payment price and settle price.

Initial version has no owner functions to not allow for owner foul play.

Written by: mousedev.eth

*/



contract MDDA is Ownable {

    uint256 public DA_STARTING_PRICE;

    uint256 public DA_ENDING_PRICE;

    uint256 public DA_DECREMENT;

    uint256 public DA_DECREMENT_FREQUENCY;

    uint256 public DA_STARTING_TIMESTAMP;

    uint256 public DA_MAX_QUANTITY;



    //The price the auction ended at.

    uint256 public DA_FINAL_PRICE;



    //The quantity for DA.

    uint256 public DA_QUANTITY;



    bool public DATA_SET;

    bool public INITIAL_FUNDS_WITHDRAWN;

    bool public REFUND_ENDED;



    //Struct for storing batch price data.

    struct TokenBatchPriceData {

        uint128 pricePaid;

        uint128 quantityMinted;

    }



    //Token to token price data

    mapping(address => TokenBatchPriceData[]) public userToTokenBatchPriceData;



    function initializeAuctionData(

        uint256 _DAStartingPrice,

        uint256 _DAEndingPrice,

        uint256 _DADecrement,

        uint256 _DADecrementFrequency,

        uint256 _DAStartingTimestamp,

        uint256 _DAMaxQuantity,

        uint256 _DAQuantity

    ) public onlyOwner {

        require(!DATA_SET, "DA data has already been set.");

        DA_STARTING_PRICE = _DAStartingPrice;

        DA_ENDING_PRICE = _DAEndingPrice;

        DA_DECREMENT = _DADecrement;

        DA_DECREMENT_FREQUENCY = _DADecrementFrequency;

        DA_STARTING_TIMESTAMP = _DAStartingTimestamp;

        DA_MAX_QUANTITY = _DAMaxQuantity;

        DA_QUANTITY = _DAQuantity;



        DATA_SET = true;

    }



    function userToTokenBatches(address user)

        public

        view

        returns (TokenBatchPriceData[] memory)

    {

        return userToTokenBatchPriceData[user];

    }



    function currentPrice() public view returns (uint256) {

        require(

            block.timestamp >= DA_STARTING_TIMESTAMP,

            "DA has not started!"

        );



        if (DA_FINAL_PRICE > 0) return DA_FINAL_PRICE;



        //Seconds since we started

        uint256 timeSinceStart = block.timestamp - DA_STARTING_TIMESTAMP;



        //How many decrements should've happened since that time

        uint256 decrementsSinceStart = timeSinceStart / DA_DECREMENT_FREQUENCY;



        //How much eth to remove

        uint256 totalDecrement = decrementsSinceStart * DA_DECREMENT;



        //If how much we want to reduce is greater or equal to the range, return the lowest value

        if (totalDecrement >= DA_STARTING_PRICE - DA_ENDING_PRICE) {

            return DA_ENDING_PRICE;

        }



        //If not, return the starting price minus the decrement.

        return DA_STARTING_PRICE - totalDecrement;

    }



    function DAHook(uint128 _quantity, uint256 _totalSupply) internal {

        require(DATA_SET, "DA data not set yet");



        uint256 _currentPrice = currentPrice();



        //Require enough ETH

        require(

            msg.value >= _quantity * _currentPrice,

            "Did not send enough eth."

        );



        require(

            _quantity > 0 && _quantity <= DA_MAX_QUANTITY,

            "Incorrect quantity!"

        );



        require(

            block.timestamp >= DA_STARTING_TIMESTAMP,

            "DA has not started!"

        );



        require(

            _totalSupply + _quantity <= DA_QUANTITY,

            "Max supply for DA reached!"

        );



        //Set the final price.

        if (_totalSupply + _quantity == DA_QUANTITY)

            DA_FINAL_PRICE = _currentPrice;



        //Add to user batch array.

        userToTokenBatchPriceData[msg.sender].push(

            TokenBatchPriceData(uint128(msg.value), _quantity)

        );

    }



    function refundExtraETH() public {

        require(DA_FINAL_PRICE > 0, "Dutch action must be over!");

        require(REFUND_ENDED == false, "Refund time has ended!");



        uint256 totalRefund;



        for (

            uint256 i = userToTokenBatchPriceData[msg.sender].length;

            i > 0;

            i--

        ) {

            //This is what they should have paid if they bought at lowest price tier.

            uint256 expectedPrice = userToTokenBatchPriceData[msg.sender][i - 1]

                .quantityMinted * DA_FINAL_PRICE;



            //What they paid - what they should have paid = refund.

            uint256 refund = userToTokenBatchPriceData[msg.sender][i - 1]

                .pricePaid - expectedPrice;



            //Remove this tokenBatch

            userToTokenBatchPriceData[msg.sender].pop();



            //Send them their extra monies.

            totalRefund += refund;

        }

        payable(msg.sender).transfer(totalRefund);

    }



    function setDAQuantity(uint256 _DAQuantity) public onlyOwner {

        DA_QUANTITY = _DAQuantity;

    }



    function setRefundEnded() public onlyOwner {

        require(REFUND_ENDED == false, "Refund time has ended!");

        REFUND_ENDED = true;

    }

}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApprovalToCurrentOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DATA_SET","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_DECREMENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_DECREMENT_FREQUENCY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_ENDING_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_FINAL_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_MAX_QUANTITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_QUANTITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_STARTING_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DA_STARTING_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_FUNDS_WITHDRAWN","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_ENDED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"chPublicSaleStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"chWhitelistSaleStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"devMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUserMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_DAStartingPrice","type":"uint256"},{"internalType":"uint256","name":"_DAEndingPrice","type":"uint256"},{"internalType":"uint256","name":"_DADecrement","type":"uint256"},{"internalType":"uint256","name":"_DADecrementFrequency","type":"uint256"},{"internalType":"uint256","name":"_DAStartingTimestamp","type":"uint256"},{"internalType":"uint256","name":"_DAMaxQuantity","type":"uint256"},{"internalType":"uint256","name":"_DAQuantity","type":"uint256"}],"name":"initializeAuctionData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"bytes32","name":"leaf","type":"bytes32"}],"name":"isValidOG","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"bytes32","name":"leaf","type":"bytes32"}],"name":"isValidWL","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_quantity","type":"uint8"}],"name":"mintDutchAuction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"ogMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintAmount","type":"uint256"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicSaleStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundExtraETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rootOG","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootWL","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_DAQuantity","type":"uint256"}],"name":"setDAQuantity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxMintAmount","type":"uint256"}],"name":"setMaxMintAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setPublicPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setRefundEnded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_rootOG","type":"bytes32"}],"name":"setRootOG","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_rootWL","type":"bytes32"}],"name":"setRootWL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setWhitelistPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userToTokenBatchPriceData","outputs":[{"internalType":"uint128","name":"pricePaid","type":"uint128"},{"internalType":"uint128","name":"quantityMinted","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userToTokenBatches","outputs":[{"components":[{"internalType":"uint128","name":"pricePaid","type":"uint128"},{"internalType":"uint128","name":"quantityMinted","type":"uint128"}],"internalType":"struct MDDA.TokenBatchPriceData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"whitelistMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"whitelistPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistSaleStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]