// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "./libs/Ownable.sol"; import "./libs/SafeMath.sol"; import "./libs/SafeERC20.sol"; import "./libs/ReentrancyGuard.sol"; import "./libs/IAlphaBetaFarm.sol"; import "./libs/Pausable.sol"; import "../StratManager.sol"; contract ABVStrat is StratManager { using SafeERC20 for IERC20; using SafeMath for uint256; // Tokens used address public output; address public want; // Third party contracts address public chef; uint256 public poolId; // Routes address[] public outputToWantRoute; bool public harvestOnDeposit = true; uint256 public lastHarvest; uint constant public WITHDRAWAL_FEE_CAP = 50; uint constant public WITHDRAWAL_MAX = 10000; uint public withdrawalFee; /** * @dev Event that is fired each time someone harvests the strat. */ event StratHarvest(address indexed harvester); constructor( address _want, address _output, address _chef, address _vault, address _keeper, uint256 _poolId ) StratManager(_keeper, address(0), address(0), _vault, address(0)) public { chef = _chef; output = _output; want = _want; poolId = _poolId; _giveAllowances(); } // puts the funds to work function deposit() public whenNotPaused { uint256 wantBal = balanceOfWant(); if (wantBal > 0) { IAlphaBetaFarm(chef).deposit(poolId, wantBal); } } function withdraw(uint256 _amount) external { require(msg.sender == vault, "!vault"); uint256 wantBal = balanceOfWant(); if (wantBal < _amount) { IAlphaBetaFarm(chef).withdraw(poolId, _amount.sub(wantBal)); wantBal = balanceOfWant(); } if (wantBal > _amount) { wantBal = _amount; } if (tx.origin == owner() || paused()) { IERC20(want).safeTransfer(vault, wantBal); } else { uint256 withdrawalFeeAmount = wantBal.mul(withdrawalFee).div(WITHDRAWAL_MAX); IERC20(want).safeTransfer(vault, wantBal.sub(withdrawalFeeAmount)); } } function beforeDeposit() external override { if (harvestOnDeposit) { require(msg.sender == vault, "!vault"); _harvest(); } } function harvest() external virtual { _harvest(); } function managerHarvest() external onlyManager { _harvest(); } // compounds earnings and charges performance fee function _harvest() internal whenNotPaused { IAlphaBetaFarm(chef).withdraw(poolId, 0); uint256 outputBal = IERC20(output).balanceOf(address(this)); if (outputBal > 0) { deposit(); lastHarvest = block.timestamp; emit StratHarvest(msg.sender); } } // calculate the total underlaying 'want' held by the strat. function balanceOf() public view returns (uint256) { return balanceOfWant().add(balanceOfPool()); } // it calculates how much 'want' this contract holds. function balanceOfWant() public view returns (uint256) { return IERC20(want).balanceOf(address(this)); } // it calculates how much 'want' the strategy has working in the farm. function balanceOfPool() public view returns (uint256) { return IAlphaBetaFarm(chef).stakedTokens(poolId, address(this)); } // called as part of strat migration. Sends all the available funds back to the vault. function retireStrat() external { require(msg.sender == vault, "!vault"); IAlphaBetaFarm(chef).withdraw(poolId, balanceOfPool()); uint256 wantBal = balanceOfWant(); IERC20(want).transfer(vault, wantBal); } function setHarvestOnDeposit(bool _harvestOnDeposit) external onlyManager { harvestOnDeposit = _harvestOnDeposit; if (harvestOnDeposit) { setWithdrawalFee(0); } else { setWithdrawalFee(5); } } function setWithdrawalFee(uint256 _fee) public onlyManager { require(_fee <= WITHDRAWAL_FEE_CAP, "!cap"); withdrawalFee = _fee; } // pauses deposits and withdraws all funds from third party systems. function panic() public onlyManager { pause(); IAlphaBetaFarm(chef).withdraw(poolId, balanceOfPool()); } function pause() public onlyManager { _pause(); _removeAllowances(); } function unpause() external onlyManager { _unpause(); _giveAllowances(); deposit(); } function outputToWant() public view returns (address[] memory) { return outputToWantRoute; } function _giveAllowances() internal { IERC20(want).safeApprove(chef, uint256(-1)); } function _removeAllowances() internal { IERC20(want).safeApprove(chef, 0); IERC20(output).safeApprove(chef, 0); } }