contract USTStrategy is BaseStrategy {    
    using SafeERC20 for IERC20;

    IAnchorRouter public constant router = IAnchorRouter(0xcEF9E167d3f8806771e9bac1d4a0d568c39a9388);
    IExchangeRateFeeder public feeder = IExchangeRateFeeder(0xB12B8247bD1749CC271c55Bb93f6BD2B485C94A7);
    IERC20 public constant UST = IERC20(0xa47c8bf37f92aBed4A126BDA807A7b7498661acD);
    IERC20 public constant aUST = IERC20(0xa8De3e3c934e2A1BB08B010104CcaBBD4D6293ab);
    address private constant degenBox = 0xd96f48665a1410C0cd669A88898ecA36B9Fc2cce;

    constructor(
        address strategyExecutor
    ) BaseStrategy(address(UST), degenBox, address(0), address(0), strategyExecutor) {
        UST.approve(address(router), type(uint256).max);
        aUST.approve(address(router), type(uint256).max);
    }
    
    function _skim(uint256 amount) internal override {
        router.depositStable(amount);
    }

    /** @inheritdoc IStrategy
    @dev Only BentoBox can call harvest on this strategy.
    @dev Ensures that (1) the caller was this contract (called through the safeHarvest function)
        and (2) that we are not being frontrun by a large BentoBox deposit when harvesting profits. */
    function harvest(uint256 balance, address sender) external override isActive onlyBentoBox returns (int256) {
        /** @dev Don't revert if conditions aren't met in order to allow
            BentoBox to continiue execution as it might need to do a rebalance. */

        if (
            sender == address(this) &&
            IBentoBoxMinimal(bentoBox).totals(strategyToken).elastic <= maxBentoBoxBalance &&
            balance > 0
        ) {
            
            int256 amount = _harvest(balance);

            /** @dev Since harvesting of rewards is accounted for seperately we might also have
            some underlying tokens in the contract that the _harvest call doesn't report. 
            E.g. reward tokens that have been sold into the underlying tokens which are now sitting in the contract.
            Meaning the amount returned by the internal _harvest function isn't necessary the final profit/loss amount */

            uint256 contractBalance = IERC20(strategyToken).balanceOf(address(this));

            if (amount >= 0) { // _harvest reported a profit

                if (contractBalance >= uint256(amount)) {
                    IERC20(strategyToken).safeTransfer(bentoBox, uint256(amount));
                    return(amount);
                } else {
                    IERC20(strategyToken).safeTransfer(bentoBox, contractBalance);
                    return int256(contractBalance);
                }

            } else { // we made a loss

                return amount;

            }

        }

        return int256(0);
    }

    function _harvest(uint256 balance) internal view override returns (int256) {
        uint256 exchangeRate = feeder.exchangeRateOf(address(UST), true);
        uint256 keep = toAUST(balance, exchangeRate);
        uint256 total = aUST.balanceOf(address(this)) + toAUST(UST.balanceOf(address(this)), exchangeRate);
        return int256(toUST(total, exchangeRate)) - int256(toUST(keep, exchangeRate));
    }

    function _withdraw(uint256 amount) internal override {
    }

    function redeemEarnings() external onlyExecutor {
        uint256 balance = IBentoBoxMinimal(bentoBox).strategyData(address(UST)).balance;
        uint256 exchangeRate = feeder.exchangeRateOf(address(UST), true);
        uint256 keep = toAUST(balance, exchangeRate);
        uint256 total = aUST.balanceOf(address(this)) + toAUST(UST.balanceOf(address(this)), exchangeRate);
        if (total > keep) router.redeemStable(total - keep);
    }

    function safeDeposit(uint256 amount) external onlyExecutor {
        _skim(amount);
    }

    function safeWithdraw(uint256 amount) external onlyExecutor {
        uint256 exchangeRate = feeder.exchangeRateOf(address(UST), true);
        uint256 requested = toAUST(amount, exchangeRate);
        router.redeemStable(requested);
    }

    function updateExchangeRateFeeder(IExchangeRateFeeder feeder_) external onlyOwner {
        feeder = feeder_;
    }

    function _exit() internal override {
        try router.redeemStable(aUST.balanceOf(address(this))) {} catch {}
    }

    function toUST(uint256 amount, uint256 exchangeRate) public pure returns (uint256) {
        return amount * exchangeRate / 1e18;
    }

    function toAUST(uint256 amount, uint256 exchangeRate) public pure returns (uint256) {
        return amount * 1e18 / exchangeRate;
    }
}
function harvest(uint256 balance, address sender) external override isActive onlyBentoBox returns (int256) {
    /** @dev Don't revert if conditions aren't met in order to allow
        BentoBox to continiue execution as it might need to do a rebalance. */

    if (
        sender == address(this) &&
        IBentoBoxMinimal(bentoBox).totals(strategyToken).elastic <= maxBentoBoxBalance &&
        balance > 0
    ) {
            
        int256 amount = _harvest(balance);

        /** @dev Since harvesting of rewards is accounted for seperately we might also have
        some underlying tokens in the contract that the _harvest call doesn't report. 
        E.g. reward tokens that have been sold into the underlying tokens which are now sitting in the contract.
        Meaning the amount returned by the internal _harvest function isn't necessary the final profit/loss amount */

        uint256 contractBalance = IERC20(strategyToken).balanceOf(address(this));

        if (amount >= 0) { // _harvest reported a profit

            if (contractBalance >= uint256(amount)) {
                IERC20(strategyToken).safeTransfer(bentoBox, uint256(amount));
                return(amount);
            } else {
                IERC20(strategyToken).safeTransfer(bentoBox, contractBalance);
                return int256(contractBalance);
            }

        } else { // we made a loss

            return amount;

        }

    }

    return int256(0);
}

/** @inheritdoc IStrategy
 @dev Only BentoBox can call harvest on this strategy.
 @dev Ensures that (1) the caller was this contract (called through the safeHarvest function)
 and (2) that we are not being frontrun by a large BentoBox deposit when harvesting profits. */