// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IStrategy {
function harvest(address _to) external;
}
interface IERC20 {
function balanceOf(address _user) external view returns (uint256);
}
contract BeefyMultiStratHarvester {
struct Config {
uint256 lowerWaitForExec;
uint256 upperWaitForExec;
uint256 gasPriceLimit;
uint256 lowerTvlLimit;
uint256 upperTvlLimit;
}
Config public config;
address[] public problemStrats;
address public beefyTreasury;
address public owner;
address public weth;
event Harvest(address[] indexed strats, uint256 time);
constructor(
address _treasury,
address _weth
) {
beefyTreasury = _treasury;
weth = _weth;
owner = msg.sender;
problemStrats.push(0xE31e2e731DE87FfD0eCE2cE2f486E9095C8eBE63);
}
modifier onlyOwner {
require(msg.sender == owner, "!Owner");
_;
}
function encodeData(address one, address two, address three, uint num) external pure returns (bytes memory) {
if (num == 1) {
return abi.encode(one);
} else if (num == 2) {
return abi.encode(one, two);
} else {
return abi.encode(one, two, three);
}
}
function decodeData(bytes memory _data, uint num) internal pure returns (address[] memory) {
if (num == 1) {
address[] memory strats = new address[](num);
address decodedAddress = abi.decode(_data, (address));
strats[0] = decodedAddress;
return strats;
} else if (num == 2) {
address[] memory strats = new address[](num);
(address one, address two) = abi.decode(_data, (address, address));
strats[0] = one;
strats[1] = two;
return strats;
} else {
(address one, address two, address three) = abi.decode(_data, (address, address, address));
address[] memory strats = new address[](num);
strats[0] = one;
strats[1] = two;
strats[2] = three;
return strats;
}
}
function harvestMultiple(bytes memory _data, uint num) external {
address[] memory strats = decodeData(_data, num);
for (uint i; i < strats.length;) {
uint256 before = IERC20(weth).balanceOf(beefyTreasury);
try IStrategy(strats[i]).harvest(beefyTreasury) {
uint256 diff = IERC20(weth).balanceOf(beefyTreasury) - before;
if (diff == 0) problemStrats.push(strats[i]);
} catch {
problemStrats.push(strats[i]);
}
unchecked { ++i; }
}
emit Harvest(strats, block.timestamp);
}
function cleanProblemStrats() external onlyOwner {
delete problemStrats;
}
function problems() external view returns (address[] memory) {
return problemStrats;
}
function transferOwnership(address _newOwner) external onlyOwner {
owner = _newOwner;
}
function setTreasury(address _treasury) external onlyOwner {
beefyTreasury = _treasury;
}
// Sets harvester configuration
function setConfig(Config calldata _config) external onlyOwner {
config = _config;
}
}
{
"compilationTarget": {
"BeefyMultiStratHarvester.sol": "BeefyMultiStratHarvester"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"strats","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"Harvest","type":"event"},{"inputs":[],"name":"beefyTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cleanProblemStrats","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"uint256","name":"lowerWaitForExec","type":"uint256"},{"internalType":"uint256","name":"upperWaitForExec","type":"uint256"},{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"lowerTvlLimit","type":"uint256"},{"internalType":"uint256","name":"upperTvlLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"one","type":"address"},{"internalType":"address","name":"two","type":"address"},{"internalType":"address","name":"three","type":"address"},{"internalType":"uint256","name":"num","type":"uint256"}],"name":"encodeData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"uint256","name":"num","type":"uint256"}],"name":"harvestMultiple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"problemStrats","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"problems","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"lowerWaitForExec","type":"uint256"},{"internalType":"uint256","name":"upperWaitForExec","type":"uint256"},{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"lowerTvlLimit","type":"uint256"},{"internalType":"uint256","name":"upperTvlLimit","type":"uint256"}],"internalType":"struct BeefyMultiStratHarvester.Config","name":"_config","type":"tuple"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]