Skip to content

Commit

Permalink
tests: fuzz tests
Browse files Browse the repository at this point in the history
  • Loading branch information
0xtekgrinder committed Jul 23, 2024
1 parent d5630e1 commit 4730bec
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 0 deletions.
Empty file removed test/fuzz/.gitkeep
Empty file.
50 changes: 50 additions & 0 deletions test/fuzz/Accumulate.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.26;

import { UtilsLib } from "morpho/libraries/UtilsLib.sol";
import "../ERC4626StrategyTest.t.sol";

contract AccumulateFuzzTest is ERC4626StrategyTest {
using UtilsLib for uint256;

function testFuzz_accumulate_Normal(
uint256 depositAmount,
uint256[5] memory timeOffsets,
uint256[5] memory balances
) public {
depositAmount = bound(depositAmount, 1e18, 1e21);
deal(asset, alice, depositAmount);

vm.startPrank(alice);
IERC20(asset).approve(address(strategy), depositAmount);
strategy.deposit(depositAmount, alice);
vm.stopPrank();

uint256 integratorShares = 0;
uint256 developerShares = 0;

for (uint256 i = 0; i < 5; i++) {
timeOffsets[i] = bound(timeOffsets[i], 1, 365 days);
vm.warp(block.timestamp + timeOffsets[i]);

balances[i] = bound(balances[i], 1, 1e22);
vm.mockCall(strategyAsset, abi.encodeWithSelector(IERC20.balanceOf.selector), abi.encode(balances[i]));
uint256 totalAssets = strategy.totalAssets();
uint256 lastTotalAssets = strategy.lastTotalAssets();

vm.mockCall(strategyAsset, abi.encodeWithSelector(IERC20.balanceOf.selector), abi.encode(balances[i]));
strategy.accumulate();

uint256 feeShare = strategy.convertToShares(
((totalAssets.zeroFloorSub(lastTotalAssets)) * strategy.performanceFee()) / strategy.BPS()
);
uint256 developerFeeShare = (feeShare * strategy.developerFee()) / strategy.BPS();

integratorShares += feeShare - developerFeeShare;
developerShares += developerFeeShare;
assertEq(strategy.lastTotalAssets(), totalAssets);
assertEq(strategy.balanceOf(strategy.integratorFeeRecipient()), integratorShares);
assertEq(strategy.balanceOf(strategy.developerFeeRecipient()), developerShares);
}
}
}
32 changes: 32 additions & 0 deletions test/fuzz/Deposit.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.26;

import "../ERC4626StrategyTest.t.sol";

contract DepositFuzzTest is ERC4626StrategyTest {
function testFuzz_Deposit_Normal(uint256[5] memory amounts) public {
for (uint256 i = 0; i < 5; i++) {
amounts[i] = bound(amounts[i], 1e18, 1e21);
deal(asset, alice, amounts[i]);

uint256 previousBalance = strategy.balanceOf(alice);
uint256 previousStrategyBalance = ERC4626(strategyAsset).balanceOf(address(strategy));

vm.startPrank(alice);
IERC20(asset).approve(address(strategy), amounts[i]);
uint256 previewedDeposit = strategy.previewDeposit(amounts[i]);
uint256 deposited = strategy.deposit(amounts[i], alice);
vm.stopPrank();

assertEq(previewedDeposit, deposited);
assertEq(
ERC4626(strategyAsset).balanceOf(address(strategy)),
previousStrategyBalance + ERC4626(strategyAsset).convertToShares(amounts[i])
);
assertEq(IERC20(asset).balanceOf(alice), 0);
assertEq(IERC20(asset).balanceOf(address(strategy)), 0);
assertEq(strategy.balanceOf(alice), previousBalance + previewedDeposit);
assertEq(strategy.totalSupply(), previousBalance + previewedDeposit);
}
}
}
34 changes: 34 additions & 0 deletions test/fuzz/Mint.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.26;

import "../ERC4626StrategyTest.t.sol";

contract MintFuzzTest is ERC4626StrategyTest {
function testFuzz_Mint_Normal(uint256[5] memory amounts) public {
for (uint256 i = 0; i < 5; i++) {
amounts[i] = bound(amounts[i], 1e18, 1e21);
deal(asset, alice, amounts[i]);

uint256 previousBalance = strategy.balanceOf(alice);
uint256 previousStrategyBalance = ERC4626(strategyAsset).balanceOf(address(strategy));

vm.startPrank(alice);
IERC20(asset).approve(address(strategy), amounts[i]);

uint256 shares = strategy.convertToShares(amounts[i]);
uint256 previewedMint = strategy.previewMint(shares);
uint256 assetsMinted = strategy.mint(shares, alice);
vm.stopPrank();

assertEq(
ERC4626(strategyAsset).balanceOf(address(strategy)),
previousStrategyBalance + ERC4626(strategyAsset).convertToShares(amounts[i])
);
assertEq(IERC20(asset).balanceOf(alice), 0);
assertEq(IERC20(asset).balanceOf(address(strategy)), 0);
assertEq(strategy.balanceOf(alice), previousBalance + shares);
assertEq(strategy.totalSupply(), previousBalance + shares);
assertEq(assetsMinted, previewedMint);
}
}
}
38 changes: 38 additions & 0 deletions test/fuzz/Redeem.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.26;

import "../ERC4626StrategyTest.t.sol";

contract RedeemFuzzTest is ERC4626StrategyTest {
function testFuzz_Redeem_Normal(uint256[5] memory amounts) public {
uint256 totalAmounts;
for (uint256 i = 0; i < 5; i++) {
amounts[i] = bound(amounts[i], 1e18, 1e21);
totalAmounts += amounts[i];
}
deal(asset, alice, totalAmounts);

vm.startPrank(alice);
IERC20(asset).approve(address(strategy), totalAmounts);
strategy.deposit(totalAmounts, alice);
vm.stopPrank();

for (uint256 i = 0; i < 5; i++) {
uint256 previousBalance = strategy.balanceOf(alice);

uint256 totalAssets = strategy.totalAssets();
uint256 lastTotalAssets = strategy.lastTotalAssets();

uint256 previousAssetBalance = IERC20(asset).balanceOf(alice);

vm.startPrank(alice);
uint256 previewedRedeem = strategy.previewRedeem(amounts[i]);
uint256 redeemed = strategy.redeem(amounts[i], alice, alice);
vm.stopPrank();

assertEq(previewedRedeem, redeemed);
assertEq(IERC20(asset).balanceOf(alice), previousAssetBalance + previewedRedeem);
assertEq(strategy.balanceOf(alice), previousBalance - amounts[i]);
}
}
}
75 changes: 75 additions & 0 deletions test/fuzz/Swap.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.26;

import { UtilsLib } from "morpho/libraries/UtilsLib.sol";
import { MockRouter } from "../mock/MockRouter.sol";
import "../ERC4626StrategyTest.t.sol";

contract SwapFuzzTest is ERC4626StrategyTest {
using UtilsLib for uint256;

MockRouter router;

function setUp() public override {
super.setUp();

router = new MockRouter();
vm.startPrank(developer);
strategy.setSwapRouter(address(router));
strategy.setTokenTransferAddress(address(router));
vm.stopPrank();
}

function testFuzz_swap_normal(
uint256[5] memory amountIns,
uint256[5] memory amountOuts,
uint256[5] memory timeOffsets
) public {
uint256 lastLockedProfit;
for (uint256 i = 0; i < 5; ++i) {
amountIns[i] = bound(amountIns[i], 1e18, 1e21);
amountOuts[i] = bound(amountOuts[i], 1e18, 1e21);
timeOffsets[i] = bound(timeOffsets[i], 1 days, 3 weeks);

deal(USDC, address(strategy), amountIns[i]);
deal(asset, address(router), amountOuts[i]);

address[] memory tokens = new address[](1);
tokens[0] = USDC;
uint256[] memory amounts = new uint256[](1);
amounts[0] = amountIns[i];
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(MockRouter.swap.selector, amountIns[i], USDC, amountOuts[i], asset);

uint256 strategyBalance = ERC4626(strategyAsset).balanceOf(address(strategy));
uint256 lockedProfit = strategy.lockedProfit();

vm.prank(keeper);
strategy.swap(tokens, data, amounts);

assertEq(IERC20(USDC).allowance(address(strategy), address(router)), 0);
assertEq(
ERC4626(strategyAsset).balanceOf(address(strategy)),
strategyBalance + ERC4626(strategyAsset).convertToShares(amountOuts[i])
);
assertEq(IERC20(asset).balanceOf(address(strategy)), 0);

assertEq(strategy.vestingProfit(), lockedProfit + amountOuts[i]);
assertEq(strategy.lastUpdate(), block.timestamp);
assertEq(
strategy.lockedProfit(),
strategy.vestingProfit() + (lastLockedProfit * timeOffsets[i]) / strategy.vestingPeriod()
);
assertEq(
strategy.totalAssets(),
ERC4626(strategyAsset)
.convertToAssets(ERC4626(strategyAsset).balanceOf(address(strategy)))
.zeroFloorSub(strategy.lockedProfit())
);

uint256 lastLockedProfit = strategy.lockedProfit();

vm.warp(block.timestamp + timeOffsets[i]);
}
}
}
49 changes: 49 additions & 0 deletions test/fuzz/Withdraw.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.26;

import { UtilsLib } from "morpho/libraries/UtilsLib.sol";
import "../ERC4626StrategyTest.t.sol";

contract WithdrawFuzzTest is ERC4626StrategyTest {
using UtilsLib for uint256;

function testFuzz_Withdraw_Normal(uint256[5] memory amounts) public {
uint256 totalAmounts;
for (uint256 i = 0; i < 5; i++) {
amounts[i] = bound(amounts[i], 1e18, 1e21);
totalAmounts += amounts[i];
}
deal(asset, alice, totalAmounts);

vm.startPrank(alice);
IERC20(asset).approve(address(strategy), totalAmounts);
strategy.deposit(totalAmounts, alice);
vm.stopPrank();

for (uint256 i = 0; i < 5; i++) {
uint256 previousBalance = strategy.balanceOf(alice);
uint256 previousAssetBalance = IERC20(asset).balanceOf(alice);

uint256 strategyAssets = ERC4626(strategyAsset).convertToAssets(
IERC20(strategyAsset).balanceOf(address(strategy))
);
vm.startPrank(alice);
if (amounts[i] >= strategyAssets) {
amounts[i] = strategyAssets;
}
uint256 previewedWithdraw = strategy.previewWithdraw(amounts[i]);
uint256 withdrawed = strategy.withdraw(amounts[i], alice, alice);
vm.stopPrank();

assertEq(previewedWithdraw, withdrawed);
assertEq(IERC20(asset).balanceOf(alice), previousAssetBalance + amounts[i]);

uint256 assetsHeld = ERC4626(strategyAsset).convertToShares(
totalAmounts - previousAssetBalance - amounts[i]
);
assertLe(IERC20(strategyAsset).balanceOf(address(strategy)), assetsHeld);
assertGe(IERC20(strategyAsset).balanceOf(address(strategy)), assetsHeld.zeroFloorSub(5));
assertEq(strategy.balanceOf(alice), previousBalance - previewedWithdraw);
}
}
}

0 comments on commit 4730bec

Please sign in to comment.