Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/slippage #122

Merged
merged 5 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions contracts/helpers/MultiBlockHarvester.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { BaseHarvester, YieldBearingParams } from "./BaseHarvester.sol";
import { ITransmuter } from "../interfaces/ITransmuter.sol";
import { IAgToken } from "../interfaces/IAgToken.sol";
import { IPool } from "../interfaces/IPool.sol";
import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";

import "../utils/Errors.sol";
import "../utils/Constants.sol";
Expand All @@ -19,6 +20,7 @@ import "../utils/Constants.sol";
/// @dev Contract to harvest yield from multiple yield bearing assets in multiple blocks transactions
contract MultiBlockHarvester is BaseHarvester {
using SafeERC20 for IERC20;
using SafeMath for uint256;

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VARIABLES
Expand Down Expand Up @@ -129,6 +131,7 @@ contract MultiBlockHarvester is BaseHarvester {
address(this),
block.timestamp
);
_checkSlippage(shares, amountOut, yieldBearingAsset, depositAddress, true);
0xtekgrinder marked this conversation as resolved.
Show resolved Hide resolved
} else if (yieldBearingAsset == USDM) {
IERC20(yieldBearingInfo.asset).safeTransfer(depositAddress, amountOut);
}
Expand Down Expand Up @@ -161,23 +164,23 @@ contract MultiBlockHarvester is BaseHarvester {
address depositAddress,
bool assetIn
) internal view {
uint256 decimalsAsset = IERC20Metadata(asset).decimals();

// Divide or multiply the amountIn to match the decimals of the asset
amountIn = _scaleAmountBasedOnDecimals(decimalsAsset, 18, amountIn, assetIn);
amountIn = _scaleAmountBasedOnDecimals(IERC20Metadata(asset).decimals(), 18, amountIn, assetIn);

uint256 result;

Check warning

Code scanning / Slither

Uninitialized local variables Medium

if (asset == USDC || asset == USDM || asset == EURC) {
// Assume 1:1 ratio between stablecoins
unchecked {
uint256 slippage = ((amountIn - amountOut) * 1e9) / amountIn;
if (slippage > maxSlippage) revert SlippageTooHigh();
}
(, result) = amountIn.trySub(amountOut);
} else if (asset == XEVT) {
// Assume 1:1 ratio between the underlying asset of the vault
unchecked {
uint256 slippage = ((IPool(depositAddress).convertToAssets(amountIn) - amountOut) * 1e9) / amountIn;
if (slippage > maxSlippage) revert SlippageTooHigh();
if (assetIn) {
(, result) = IPool(depositAddress).convertToAssets(amountIn).trySub(amountOut);
} else {
(, result) = amountIn.trySub(IPool(depositAddress).convertToAssets(amountOut));
}
} else revert InvalidParam();

uint256 slippage = (result * 1e9) / amountIn;
if (slippage > maxSlippage) revert SlippageTooHigh();
}
}
33 changes: 17 additions & 16 deletions test/fuzz/MultiBlockHarvester.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ contract MultiBlockHarvestertTest is Fixture, FunctionUtils {
)
);

oracleXEVT = AggregatorV3Interface(address(new MockChainlinkOracle()));
circuitChainlink[0] = AggregatorV3Interface(oracleXEVT);
readData = abi.encode(circuitChainlink, stalePeriods, circuitChainIsMultiplied, chainlinkDecimals, quoteType);
MockChainlinkOracle(address(oracleXEVT)).setLatestAnswer(int256(BASE_8));
address oracle = 0x6B102047A4bB943DE39233E44487F2d57bDCb33e;
uint256 normalizationFactor = 1e18; // price == 36 decimals
readData = bytes("");
targetData = abi.encode(oracle, normalizationFactor);
transmuter.setOracle(
XEVT,
abi.encode(
OracleReadType.CHAINLINK_FEEDS,
OracleReadType.STABLE,
OracleReadType.NO_ORACLE,
OracleReadType.MORPHO_ORACLE,
readData,
targetData,
abi.encode(uint128(0), uint128(0))
Expand Down Expand Up @@ -179,6 +179,8 @@ contract MultiBlockHarvestertTest is Fixture, FunctionUtils {
harvester.setYieldBearingToDepositAddress(XEVT, XEVT);
harvester.setYieldBearingToDepositAddress(USDM, receiver);

transmuter.toggleTrusted(address(harvester), TrustedType.Seller);

agToken.mint(address(harvester), 1_000_000e18);

vm.stopPrank();
Expand Down Expand Up @@ -358,7 +360,7 @@ contract MultiBlockHarvestertTest is Fixture, FunctionUtils {
}

function test_harvest_IncreaseExposureXEVT(uint256 amount) external {
amount = 7022;
amount = bound(amount, 1e3, 1e11);
_loadReserve(EURC, amount);
_setYieldBearingData(XEVT, EURC);

Expand Down Expand Up @@ -399,7 +401,6 @@ contract MultiBlockHarvestertTest is Fixture, FunctionUtils {

assertEq(expectedIncrease, 0);
assertEq(issuedFromStablecoinBefore, 0);
assertEq(issuedFromYieldBearingAssetBefore, amount * 1e12);
assertEq(totalIssuedBefore, issuedFromYieldBearingAssetBefore);
assertEq(expectedAmount, issuedFromYieldBearingAssetBefore - ((targetExposure * totalIssuedBefore) / 1e9));

Expand Down Expand Up @@ -520,13 +521,13 @@ contract MultiBlockHarvestertTest is Fixture, FunctionUtils {
}

function test_ComputeRebalanceAmount_HigherThanMaxWithHarvest() external {
_loadReserve(XEVT, 1e11);
_loadReserve(EURC, 1e11);
_loadReserve(USDC, 1e11);
_loadReserve(USDM, 1e23);
uint64 minExposure = uint64((15 * 1e9) / 100);
uint64 maxExposure = uint64((60 * 1e9) / 100);
_setYieldBearingData(XEVT, EURC, minExposure, maxExposure);
_setYieldBearingData(USDM, USDC, minExposure, maxExposure);

(uint8 increase, uint256 amount) = harvester.computeRebalanceAmount(XEVT);
(uint8 increase, uint256 amount) = harvester.computeRebalanceAmount(USDM);
assertEq(amount, (2e23 * uint256(maxExposure)) / 1e9 - 1e23);
assertEq(increase, 0);
}
Expand All @@ -544,13 +545,13 @@ contract MultiBlockHarvestertTest is Fixture, FunctionUtils {
}

function test_ComputeRebalanceAmount_LowerThanMinAfterHarvest() external {
_loadReserve(EURC, 9e10);
_loadReserve(XEVT, 1e10);
_loadReserve(USDC, 9e10);
_loadReserve(USDM, 1e22);
uint64 minExposure = uint64((89 * 1e9) / 100);
uint64 maxExposure = uint64((999 * 1e9) / 1000);
_setYieldBearingData(XEVT, EURC, minExposure, maxExposure);
_setYieldBearingData(USDM, USDC, minExposure, maxExposure);

(uint8 increase, uint256 amount) = harvester.computeRebalanceAmount(XEVT);
(uint8 increase, uint256 amount) = harvester.computeRebalanceAmount(USDM);
assertEq(amount, 9e22 - (1e23 * uint256(minExposure)) / 1e9);
assertEq(increase, 1);
}
Expand Down
Loading