generated from AngleProtocol/boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d5630e1
commit 4730bec
Showing
7 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |