// File: src/policies/Distributor/ZeroDistributor.sol



// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

import {IDistributor} from "src/policies/interfaces/IDistributor.sol";
import {IStaking} from "src/interfaces/IStaking.sol";

contract ZeroDistributor is IDistributor {
    IStaking public immutable staking;
    bool private unlockRebase;

    constructor(address staking_) {
        staking = IStaking(staking_);
    }

    /// @notice Trigger 0 rebase via distributor. There is an error in Staking's stake function
    ///         which pulls forward part of the rebase for the next epoch. This path triggers a
    ///         rebase by calling unstake (which does not have the issue). The patch also
    ///         restricts distribute to only be able to be called from a tx originating in this
    ///         function.
    function triggerRebase() external {
        unlockRebase = true;
        staking.unstake(address(this), 0, true, true);
        if (unlockRebase) unlockRebase = false;
    }

    /// @notice Endpoint must be available for Staking to call. Zero emission.
    function distribute() external {
        if (msg.sender != address(staking)) revert Distributor_OnlyStaking();
        if (!unlockRebase) revert Distributor_NotUnlocked();
        unlockRebase = false;
    }

    /// @notice Endpoint must be available for Staking to call. Zero emission.
    function retrieveBounty() external pure returns (uint256) {
        return 0;
    }
}

// File: src/policies/interfaces/IDistributor.sol



// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;

interface IDistributor {
    // =========  ERRORS ========= //

    error Distributor_NoRebaseOccurred();
    error Distributor_OnlyStaking();
    error Distributor_NotUnlocked();

    // =========  CORE FUNCTIONS ========= //

    /// @notice Trigger rebases via distributor. There is an error in Staking's `stake` function
    ///         which pulls forward part of the rebase for the next epoch. This path triggers a
    ///         rebase by calling `unstake` (which does not have the issue). The patch also
    ///         restricts `distribute` to only be able to be called from a tx originating in this
    ///         function.
    function triggerRebase() external;

    /// @notice Send the epoch's reward to the staking contract, and mint rewards to Uniswap V2 pools.
    ///         This removes opportunity cost for liquidity providers by sending rebase rewards
    ///         directly into the liquidity pool.
    ///
    ///         NOTE: This does not add additional emissions (user could be staked instead and get the
    ///         same tokens).
    function distribute() external;

    /// @notice Mints the bounty (if > 0) to the staking contract for distribution.
    /// @return uint256 The amount of OHM minted as a bounty.
    function retrieveBounty() external returns (uint256);
}

// File: src/interfaces/IStaking.sol



// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

interface IStaking {
    /* ========== DATA STRUCTURES ========== */

    struct Epoch {
        uint256 length; // in seconds
        uint256 number; // since inception
        uint256 end; // timestamp
        uint256 distribute; // amount
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    function rebase() external returns (uint256);

    function unstake(address, uint256, bool _trigger, bool) external returns (uint256);

    /* ========== ADMIN FUNCTIONS ========== */

    function setDistributor(address _distributor) external;

    /* ========== VIEW FUNCTIONS ========== */

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