contract DAOVaultLowUSDC is ERC20, Ownable {
    using SafeERC20 for IERC20;
    using Address for address;
    using SafeMath for uint256;

    IERC20 public token;
    IStrategy public strategy;
    address public pendingStrategy;

    bool public canSetPendingStrategy = true;
    uint256 public unlockTime;
    uint256 public constant LOCKTIME = 2 days;

    event MigrateFunds(
        address indexed fromStrategy,
        address indexed toStrategy,
        uint256 amount
    );

    constructor(address _token, address _strategy)
        ERC20("DAO Vault Low USDC", "dvlUSDC")
    {
        token = IERC20(_token);
        _setupDecimals(6);
        strategy = IStrategy(_strategy);
    }

    /**
     * @notice Deposit into strategy
     * @param _amount amount to deposit
     * Requirements:
     * - Only EOA account can call this function
     */
    function deposit(uint256 _amount) external {
        require(!address(msg.sender).isContract(), "Only EOA");
        require(_amount > 0, "Amount must > 0");

        uint256 _before = strategy.balanceOf(address(this));
        strategy.deposit(_amount);
        uint256 _after = strategy.balanceOf(address(this));
        _mint(msg.sender, _after.sub(_before));
    }

    /**
     * @notice Withdraw from strategy
     * @param _amount shares to withdraw
     * Requirements:
     * - Only EOA account can call this function
     */
    function withdraw(uint256 _amount) external {
        require(!address(msg.sender).isContract(), "Only EOA");
        require(_amount > 0, "Amount must > 0");

        uint256 _before = strategy.balanceOf(address(this));
        strategy.withdraw(_amount);
        uint256 _after = strategy.balanceOf(address(this));
        _burn(msg.sender, _before.sub(_after));
    }

    /**
     * @notice Refund from strategy
     * @notice This function usually only available when strategy in vesting state
     * Requirements:
     * - Only EOA account can call this function
     * - Amount daoToken of user must greater than 0
     */
    function refund() external {
        require(!address(msg.sender).isContract(), "Only EOA");
        require(balanceOf(msg.sender) > 0, "No balance to refund");

        uint256 _shares = balanceOf(msg.sender);
        uint256 _before = strategy.balanceOf(address(this));
        strategy.refund(_shares);
        uint256 _after = strategy.balanceOf(address(this));
        _burn(msg.sender, _before.sub(_after));
    }

    /**
     * @notice Set pending strategy
     * @param _pendingStrategy Address of pending strategy
     * Requirements:
     * - Only owner of this contract call this function
     * - Pending strategy must be a contract
     */
    function setPendingStrategy(address _pendingStrategy) external onlyOwner {
        require(
            canSetPendingStrategy,
            "Cannot set pending strategy now"
        );
        require(
            _pendingStrategy.isContract(),
            "New strategy is not contract"
        );

        pendingStrategy = _pendingStrategy;
    }

    /**
     * @notice Unlock function migrateFunds()
     * Requirements:
     * - Only owner of this contract call this function
     */
    function unlockMigrateFunds() external onlyOwner {
        unlockTime = block.timestamp + LOCKTIME;
        canSetPendingStrategy = false;
    }

    /**
     * @notice Migrate all funds from old strategy to new strategy
     * Requirements:
     * - Only owner of this contract call this function
     * - This contract is not locked
     * - Pending strategy is set
     */
    function migrateFunds() external onlyOwner {
        require(
            unlockTime <= block.timestamp &&
                unlockTime + 1 days >= block.timestamp,
            "Function locked"
        );
        require(
            token.balanceOf(address(strategy)) > 0,
            "No balance to migrate"
        );
        require(pendingStrategy != address(0), "No pendingStrategy");
        uint256 _amount = token.balanceOf(address(strategy));

        token.safeTransferFrom(address(strategy), pendingStrategy, _amount);
        // Remove balance of old strategy token
        IERC20 oldStrategyToken = IERC20(address(strategy));
        oldStrategyToken.safeTransfer(
            address(strategy),
            oldStrategyToken.balanceOf(address(this))
        );

        // Set new strategy
        address oldStrategy = address(strategy);
        strategy = IStrategy(pendingStrategy);
        pendingStrategy = address(0);
        canSetPendingStrategy = true;

        unlockTime = 0; // Lock back this function
        emit MigrateFunds(oldStrategy, address(strategy), _amount);
    }
}
/// @title Contract to interact between user and strategy, and distribute daoToken
function migrateFunds() external onlyOwner {
    require(
        unlockTime <= block.timestamp &&
            unlockTime + 1 days >= block.timestamp,
        "Function locked"
    );
    require(
        token.balanceOf(address(strategy)) > 0,
        "No balance to migrate"
    );
    require(pendingStrategy != address(0), "No pendingStrategy");
    uint256 _amount = token.balanceOf(address(strategy));

    token.safeTransferFrom(address(strategy), pendingStrategy, _amount);
    // Remove balance of old strategy token
    IERC20 oldStrategyToken = IERC20(address(strategy));
    oldStrategyToken.safeTransfer(
        address(strategy),
        oldStrategyToken.balanceOf(address(this))
    );

    // Set new strategy
    address oldStrategy = address(strategy);
    strategy = IStrategy(pendingStrategy);
    pendingStrategy = address(0);
    canSetPendingStrategy = true;

    unlockTime = 0; // Lock back this function
    emit MigrateFunds(oldStrategy, address(strategy), _amount);
}

/**
 * @notice Migrate all funds from old strategy to new strategy
 * Requirements:
 * - Only owner of this contract call this function
 * - This contract is not locked
 * - Pending strategy is set
 */