// Contract: Proposal32
// Target function: function compStream(address _address, uint256 amountYAM) internal
 (uint256) {
        epoch;
        indexDelta;
        positive;
        delegateAndReturn();
    }

    /**
     * @dev Decrease the amount of tokens that an owner has allowed to a spender.
     *
     * @param spender The address which will spend the funds.
     * @param subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue)
        external
        override
        returns (bool)
    {
        spender;
        subtractedValue; // Shh
        delegateAndReturn();
    }

    // --- Approve by signature ---
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        owner;
        spender;
        value;
        deadline;
        v;
        r;
        s; // Shh
        delegateAndReturn();
    }

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param owner The address of the account which owns the tokens to be spent
     * @param spender The address of the account which may transfer tokens
     * @return The number of tokens allowed to be spent (-1 means infinite)
     */
    function allowance(address owner, address spender)
        external
        view
        override
        returns (uint256)
    {
        owner;
        spender; // Shh
        delegateToViewAndReturn();
    }

    /**
     * @notice Rescues tokens and sends them to the `to` address
     * @param token The address of the token
     * @param to The address for which the tokens should be send
     * @return Success
     */
    function rescueTokens(
        address token,
        address to,
        uint256 amount
    ) external returns (bool) {
        token;
        to;
        amount; // Shh
        delegateAndReturn();
    }

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param delegator The address of the account which has designated a delegate
     * @return Address of delegatee
     */
    function delegates(address delegator)
        external
        view
        override
        returns (address)
    {
        delegator; // Shh
        delegateToViewAndReturn();
    }

    /**
     * @notice Get the token balance of the `owner`
     * @param owner The address of the account to query
     * @return The number of tokens owned by `owner`
     */
    function balanceOf(address owner) external view override returns (uint256) {
        owner; // Shh
        delegateToViewAndReturn();
    }

    /**
     * @notice Currently unused. For future compatability
     * @param owner The address of the account to query
     * @return The number of underlying tokens owned by `owner`
     */
    function balanceOfUnderlying(address owner)
        external
        view
        override
        returns (uint256)
    {
        owner; // Shh
        delegateToViewAndReturn();
    }

    /*** Gov Functions ***/

    /**
     * @notice Begins transfer of gov rights. The newPendingGov must call `_acceptGov` to finalize the transfer.
     * @dev Gov function to begin change of gov. The newPendingGov must call `_acceptGov` to finalize the transfer.
     * @param newPendingGov New pending gov.
     */
    function _setPendingGov(address newPendingGov) external override {
        newPendingGov; // Shh
        delegateAndReturn();
    }

    function _setRebaser(address rebaser_) external override {
        rebaser_; // Shh
        delegateAndReturn();
    }

    function _setIncentivizer(address incentivizer_) external override {
        incentivizer_; // Shh
        delegateAndReturn();
    }

    function _setMigrator(address migrator_) external {
        migrator_; // Shh
        delegateAndReturn();
    }

    /**
     * @notice Accepts transfer of gov rights. msg.sender must be pendingGov
     * @dev Gov function for pending gov to accept role and update gov
     */
    function _acceptGov() external override {
        delegateAndReturn();
    }

    function getPriorVotes(address account, uint256 blockNumber)
        external
        view
        override
        returns (uint256)
    {
        account;
        blockNumber;
        delegateToViewAndReturn();
    }

    function delegateBySig(
        address delegatee,
        uint256 nonce,
        uint256 expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override {
        delegatee;
        nonce;
        expiry;
        v;
        r;
        s;
        delegateAndReturn();
    }

    function delegate(address delegatee) external override {
        delegatee;
        delegateAndReturn();
    }

    function getCurrentVotes(address account)
        external
        view
        override
        returns (uint256)
    {
        account;
        delegateToViewAndReturn();
    }

    function yamToFragment(uint256 yam)
        external
        view
        override
        returns (uint256)
    {
        yam;
        delegateToViewAndReturn();
    }

    function fragmentToYam(uint256 value)
        external
        view
        override
        returns (uint256)
    {
        value;
        delegateToViewAndReturn();
    }

    /**
     * @notice Internal method to delegate execution to another contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     * @param callee The contract to delegatecall
     * @param data The raw data to delegatecall
     * @return The returned bytes from the delegatecall
     */
    function delegateTo(address callee, bytes memory data)
        internal
        returns (bytes memory)
    {
        (bool success, bytes memory returnData) = callee.delegatecall(data);
        assembly {
            if eq(success, 0) {
                revert(add(returnData, 0x20), returndatasize())
            }
        }
        return returnData;
    }

    /**
     * @notice Delegates execution to the implementation contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     * @param data The raw data to delegatecall
     * @return The returned bytes from the delegatecall
     */
    function delegateToImplementation(bytes memory data)
        public
        returns (bytes memory)
    {
        return delegateTo(implementation, data);
    }

    /**
     * @notice Delegates execution to an implementation contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     *  There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
     * @param data The raw data to delegatecall
     * @return The returned bytes from the delegatecall
     */
    function delegateToViewImplementation(bytes memory data)
        public
        view
        returns (bytes memory)
    {
        (bool success, bytes memory returnData) = address(this).staticcall(
            abi.encodeWithSignature("delegateToImplementation(bytes)", data)
        );
        assembly {
            if eq(success, 0) {
                revert(add(returnData, 0x20), returndatasize())
            }
        }
        return abi.decode(returnData, (bytes));
    }

    function delegateToViewAndReturn() private view returns (bytes memory) {
        (bool success, ) = address(this).staticcall(
            abi.encodeWithSignature("delegateToImplementation(bytes)", msg.data)
        );

        assembly {
            let free_mem_ptr := mload(0x40)
            returndatacopy(free_mem_ptr, 0, returndatasize())

            switch success
            case 0 {
                revert(free_mem_ptr, returndatasize())
            }
            default {
                return(add(free_mem_ptr, 0x40), sub(returndatasize(), 0x40))
            }
        }
    }

    function delegateAndReturn() private returns (bytes memory) {
        (bool success, ) = implementation.delegatecall(msg.data);

        assembly {
            let free_mem_ptr := mload(0x40)
            returndatacopy(free_mem_ptr, 0, returndatasize())

            switch success
            case 0 {
                revert(free_mem_ptr, returndatasize())
            }
            default {
                return(free_mem_ptr, returndatasize())
            }
        }
    }

    /**
     * @notice Delegates execution to an implementation contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     */
    fallback() external {
        // require(msg.value == 0,"YAMDelegator:fallback: cannot send value to fallback");

        // delegate all other functions to current implementation
        delegateAndReturn();
    }
}

////// contracts/2022/09/Proposal32.sol
/* pragma solidity 0.8.10; */

/* import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol"; */
/* import {YAMTokenInterface} from "../../../utils/YAMTokenInterface.sol"; */
/* import {UniswapV2Router02} from "../../../utils/UniswapV2Router02.sol"; */
/* import {ISablier} from "../../../utils/Sablier.sol"; */
/* import "../../../utils/YAMDelegator.sol"; */

interface IYVault {
    function deposit(uint256 amount, address recipient)
        external
        returns (uint256);

    function withdraw(uint256 amount) external returns (uint256);
}

contract Proposal32 {
    /// Contracts and ERC20 addresses
    IERC20 internal constant WETH =
        IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    IERC20 internal constant YAM =
        IERC20(0x0AaCfbeC6a24756c20D41914F2caba817C0d8521);
    YAMTokenInterface internal constant YAMV3 =
        YAMTokenInterface(0x0AaCfbeC6a24756c20D41914F2caba817C0d8521);
    IYVault internal constant yUSDC =
        IYVault(0xa354F35829Ae975e850e23e9615b11Da1B3dC4DE);
    IERC20 internal constant USDC =
        IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
    IERC20 internal constant YAMSLP =
        IERC20(0x0F82E57804D0B1F6FAb2370A43dcFAd3c7cB239c);
    UniswapV2Router02 internal constant Sushiswap =
        UniswapV2Router02(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
    ISablier internal constant Sablier =
        ISablier(0xCD18eAa163733Da39c232722cBC4E8940b1D8888);
    address internal constant RESERVES =
        0x97990B693835da58A281636296D2Bf02787DEa17;
    address internal constant MULTISIG =
        0x744D16d200175d20E6D8e5f405AEfB4EB7A962d1;
    address internal constant TIMELOCK =
        0x8b4f1616751117C38a0f84F9A146cca191ea3EC5;
    uint8 executeStep = 0;

    function execute() public {
        // Withdraw USDC
        withdrawToken(
            address(USDC),
            address(this),
            IERC20(USDC).balanceOf(RESERVES)
        );

        // Comp transfers

        // // E
        // compSend(0x8A8acf1cEcC4ed6Fe9c408449164CE2034AdC03f, 0, 0, 1);
        // // Chilly
        // compSend(0x01e0C7b70E0E05a06c7cC8deeb97Fa03d6a77c9C, 0, 0, 1);
        // // Designer
        // compSend(0x3FdcED6B5C1f176b543E5E0b841cB7224596C33C, 0, 0, 1);
        // Ross
        compSend(0x88c868B1024ECAefDc648eb152e91C57DeA984d0, 6438, 0, 1);
        // // Feddas
        // compSend(0xbdac5657eDd13F47C3DD924eAa36Cf1Ec49672cc, 0, 0, 1);
        // // Mona
        // compSend(0xdADc6F71986643d9e9CB368f08Eb6F1333F6d8f9, 0, 0, 1);

        // Transfer remaining USDC to reserves
        uint256 usdcBalance = USDC.balanceOf(address(this));
        USDC.transfer(RESERVES, usdcBalance);

        executeStep++;
    }

    function executeStreams() public {
        require(executeStep == 1);

        // Approve Sablier
        YAM.approve(address(Sablier), type(uint256).max);

        // Yam vesting

        // E
        compStream(0x8A8acf1cEcC4ed6Fe9c408449164CE2034AdC03f, 110150);
        // // Chilly
        // compStream(0x01e0C7b70E0E05a06c7cC8deeb97Fa03d6a77c9C, 0);
        // // Designer
        // compStream(0x3FdcED6B5C1f176b543E5E0b841cB7224596C33C, 0);
        // Ross
        compStream(0x88c868B1024ECAefDc648eb152e91C57DeA984d0, 7411);
        // Feddas
        compStream(0xbdac5657eDd13F47C3DD924eAa36Cf1Ec49672cc, 19173);
        // Jpgs
        compStream(0x653d63E4F2D7112a19f5Eb993890a3F27b48aDa5, 25564);

        executeStep++;
    }

    function createPOL(
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin
    ) public {
        // require(msg.sender == 0x744D16d200175d20E6D8e5f405AEfB4EB7A962d1);

        // Withdraw WETH
        withdrawToken(
            address(WETH),
            address(this),
            IERC20(WETH).balanceOf(RESERVES)
        );

        // Approve Sushiswap
        WETH.approve(address(Sushiswap), type(uint256).max);
        YAM.approve(address(Sushiswap), type(uint256).max);

        // Add liquidity
        Sushiswap.addLiquidity(
            address(YAM),
            address(WETH),
            amountADesired,
            amountBDesired,
            amountAMin,
            amountBMin,
            address(this),
            block.timestamp + 500
        );

        // Transfer remaining WETH to reserves
        uint256 wethBalance = WETH.balanceOf(address(this));
        WETH.transfer(RESERVES, wethBalance);

        // Transfer YAMSLP tokens to reserves
        uint256 slpBalance = YAMSLP.balanceOf(address(this));
        YAMSLP.transfer(RESERVES, slpBalance);

        // Burn leftovers
        YAMV3.burn(YAM.balanceOf(address(this)));
    }

    // Function to withdraw from treasury
    function withdrawToken(
        address tokenAddress,
        address toAddress,
        uint256 amount
    ) internal {
        IERC20(tokenAddress).transferFrom(RESERVES, toAddress, amount);
    }

    // Function to distribute comps
    function compSend(
        address _address,
        uint256 amountUSDC,
        uint256 amountYAM,
        uint256 months
    ) internal {
        if (amountUSDC > 0) {
            USDC.transfer(_address, amountUSDC * (10**6) * months);
        }
        if (amountYAM > 0) {
            YAM.transfer(_address, amountYAM * (10**18) * months);
        }
    }