Skip to content

Commit

Permalink
feat: auto health check
Browse files Browse the repository at this point in the history
  • Loading branch information
Schlagonia committed Oct 28, 2023
1 parent 81a47eb commit cb21fd1
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 89 deletions.
23 changes: 20 additions & 3 deletions src/HealthCheck/BaseHealthCheck.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import {BaseStrategy, ERC20} from "@tokenized-strategy/BaseStrategy.sol";
* `checkHealth` modifier.
*
* A strategist simply needs to inherit this contract. Set
* the limit ratios to the desired amounts and then call
* `_executeHealthCheck(...)` during the `_harvestAndReport()`
* execution. If the profit or loss that would be recorded is
* the limit ratios to the desired amounts and then
* override `_harvestAndReport()` just as they otherwise
* would. If the profit or loss that would be recorded is
* outside the acceptable bounds the tx will revert.
*
* The healthcheck does not prevent a strategy from reporting
Expand Down Expand Up @@ -109,6 +109,23 @@ abstract contract BaseHealthCheck is BaseStrategy {
doHealthCheck = _doHealthCheck;
}

/**
* @notice OVerrides the default {harvestAndReport} to include a healthcheck.
* @return _totalAssets New totalAssets post report.
*/
function harvestAndReport()
external
override
onlySelf
returns (uint256 _totalAssets)
{
// Let the strategy report.
_totalAssets = _harvestAndReport();

// Run the healthcheck on the amount returned.
_executeHealthCheck(_totalAssets);
}

/**
* @dev To be called during a report to make sure the profit
* or loss being recorded is within the acceptable bound.
Expand Down
51 changes: 0 additions & 51 deletions src/test/HealthCheck.sol → src/test/HealthCheck.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -428,55 +428,4 @@ contract HealthCheckTest is Setup {
"doHealthCheck should be true"
);
}

function test__checkHealthModifier(uint256 _amount) public {
vm.assume(_amount >= minFuzzAmount && _amount <= maxFuzzAmount);

// deposit
mintAndDepositIntoStrategy(
IStrategy(address(healthCheck)),
user,
_amount
);

assertEq(healthCheck.healthy(), true);
assertEq(healthCheck.availableDepositLimit(user), type(uint256).max);
assertEq(healthCheck.availableWithdrawLimit(user), type(uint256).max);

healthCheck.setHealthy(false);

assertEq(healthCheck.healthy(), false);
assertEq(healthCheck.availableDepositLimit(user), 0);
assertEq(healthCheck.availableWithdrawLimit(user), 0);

vm.expectRevert("unhealthy");
vm.prank(keeper);
healthCheck.report();

healthCheck.setHealthy(true);

assertEq(healthCheck.healthy(), true);
assertEq(healthCheck.availableDepositLimit(user), type(uint256).max);
assertEq(healthCheck.availableWithdrawLimit(user), type(uint256).max);

vm.prank(keeper);
(uint256 realProfit, ) = healthCheck.report();

// Make sure we reported the correct profit
assertEq(0, realProfit, "Reported profit mismatch");

// Health Check should still be on
assertEq(
healthCheck.doHealthCheck(),
true,
"doHealthCheck should be true"
);

skip(healthCheck.profitMaxUnlockTime());

vm.prank(user);
healthCheck.redeem(_amount, user, user);

assertGe(asset.balanceOf(user), _amount);
}
}
36 changes: 1 addition & 35 deletions src/test/mocks/MockHealthCheck.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,10 @@ contract MockHealthCheck is BaseHealthCheck {
override
returns (uint256 _totalAssets)
{
require(_healthy(), "unhealthy");

_totalAssets = asset.balanceOf(address(this));

_executeHealthCheck(_totalAssets);
}

// Can't deposit if its not healthy
function availableDepositLimit(
address _owner
) public view override returns (uint256) {
if (!_healthy()) return 0;

return super.availableDepositLimit(_owner);
}

// Can't Withdraw if not healthy.
function availableWithdrawLimit(
address _owner
) public view override returns (uint256) {
if (!_healthy()) return 0;

return super.availableWithdrawLimit(_owner);
}

function _healthy() internal view returns (bool) {
return healthy;
}

function setHealthy(bool _health) external {
healthy = _health;
}
}

import {IBaseHealthCheck} from "../../HealthCheck/IBaseHealthCheck.sol";

interface IMockHealthCheck is IBaseHealthCheck {
function healthy() external view returns (bool);

function setHealthy(bool _health) external;
}
interface IMockHealthCheck is IBaseHealthCheck {}

0 comments on commit cb21fd1

Please sign in to comment.