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 exisiting unit tests #54

Merged
merged 17 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 10 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
14 changes: 14 additions & 0 deletions src/interfaces/term/ITermAuctionOfferLocker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ interface ITermAuctionOfferLocker {
bool isRevealed;
}

/// @dev TermAuctionRevealedOffer represents a revealed offer to offeror an amount of money for a specific interest rate
struct TermAuctionRevealedOffer {
/// @dev Unique identifier for this bid
bytes32 id;
/// @dev The address of the offeror
address offeror;
/// @dev The offered price as a percentage of the initial loaned amount vs amount returned at maturity. This stores 9 decimal places
uint256 offerPriceRevealed;
/// @dev The maximum amount of purchase tokens offered
uint256 amount;
/// @dev The address of the lent ERC20 token
address purchaseToken;
}

function termRepoId() external view returns (bytes32);

function termAuctionId() external view returns (bytes32);
Expand Down
111 changes: 111 additions & 0 deletions src/test/TestUSDCIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import {MockUSDC} from "./mocks/MockUSDC.sol";
import {Setup, ERC20, IStrategyInterface} from "./utils/Setup.sol";
import {Strategy} from "../Strategy.sol";

import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {TermDiscountRateAdapter} from "../TermDiscountRateAdapter.sol";
import {RepoTokenList} from "../RepoTokenList.sol";



contract TestUSDCIntegration is Setup {
uint256 internal constant TEST_REPO_TOKEN_RATE = 0.05e18;
uint256 public constant THREESIXTY_DAYCOUNT_SECONDS = 360 days;
Expand Down Expand Up @@ -150,6 +156,111 @@ contract TestUSDCIntegration is Setup {
assertTrue(offers[0] == offerId1 ? address(repoToken1WeekAuction) <= address(repoToken1MonthAuction) : address(repoToken1MonthAuction) <= address(repoToken1WeekAuction));
}

function testRemovingMaturedTokensWithRedemptionAttempt() public {
address testUser = vm.addr(0x11111);
mockUSDC.mint(testUser, 1e18);
repoToken1Month.mint(testUser, 1000e18);

vm.startPrank(testUser);
mockUSDC.approve(address(mockYearnVault), type(uint256).max);
mockYearnVault.deposit(1e18, testUser);
repoToken1Month.approve(address(strategy), type(uint256).max);
termStrategy.sellRepoToken(address(repoToken1Month), 1e6);
vm.stopPrank();

address[] memory holdings = termStrategy.repoTokenHoldings();
assertEq(holdings.length, 1);


vm.warp(block.timestamp + 5 weeks);
termStrategy.auctionClosed();

holdings = termStrategy.repoTokenHoldings();
assertEq(holdings.length, 0);
assertEq(repoToken1Month.balanceOf(address(strategy)), 0);
}
Comment on lines +191 to +213
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add redemption attempt to match the test function name

The test function testRemovingMaturedTokensWithRedemptionAttempt does not include an attempt to redeem the matured tokens, despite the implication in its name. Consider adding logic to attempt redemption and verify the outcome to fully cover the intended scenario.

Apply this diff to include the redemption attempt:

     assertEq(holdings.length, 0);
+    // Attempt to redeem the matured tokens
+    uint256 redeemedAmount = termStrategy.redeemMaturedTokens();
+    // Verify the redeemed amount is as expected
+    assertEq(redeemedAmount, expectedRedeemedAmount);
+    // Ensure the repo token balance is zero after redemption
+    assertEq(repoToken1Month.balanceOf(address(strategy)), 0);
 }

Replace expectedRedeemedAmount with the expected amount after redemption.

Committable suggestion was skipped due to low confidence.


function testSimulateTransactionWithInvalidToken() public {
address testUser = vm.addr(0x11111);

vm.prank(management);
termController.markNotTermDeployed(address(repoToken1Week));
vm.stopPrank();

vm.prank(testUser);
vm.expectRevert(abi.encodeWithSelector(RepoTokenList.InvalidRepoToken.selector, address(repoToken1Week)));
termStrategy.simulateTransaction(address(repoToken1Week), 1e6);
}


function testRepoTokenBlacklist() public {
address testUser = vm.addr(0x11111);
vm.prank(testUser);
vm.expectRevert("!management");
termStrategy.setRepoTokenBlacklist(address(repoToken1Week), true);
vm.stopPrank();

vm.prank(management);
termStrategy.setRepoTokenBlacklist(address(repoToken1Week), true);
vm.stopPrank();

vm.prank(testUser);
vm.expectRevert(abi.encodeWithSelector(Strategy.RepoTokenBlacklisted.selector, address(repoToken1Week)));
termStrategy.sellRepoToken(address(repoToken1Week), 1e6);
}

function testPauses() public {
address testUser = vm.addr(0x11111);
mockUSDC.mint(testUser, 1e18);
vm.prank(testUser);
vm.expectRevert("!management");
termStrategy.pauseDeposit();
vm.expectRevert("!management");
termStrategy.unpauseDeposit();
vm.stopPrank();

vm.prank(management);
termStrategy.pauseDeposit();
vm.stopPrank();

vm.prank(testUser);
mockUSDC.approve(address(termStrategy), 1e6);

vm.prank(testUser);
vm.expectRevert(abi.encodeWithSelector(Strategy.DepositPaused.selector));
IERC4626(address(termStrategy)).deposit(1e6, testUser);
vm.stopPrank();

vm.prank(management);
termStrategy.unpauseDeposit();
vm.stopPrank();

vm.prank(testUser);
IERC4626(address(termStrategy)).deposit(1e6, testUser);
vm.stopPrank();
}

function testSetDiscountRateAdapter() public {
address testUser = vm.addr(0x11111);

TermDiscountRateAdapter invalid = new TermDiscountRateAdapter(address(0), adminWallet);
TermDiscountRateAdapter valid = new TermDiscountRateAdapter(address(termController), adminWallet);

vm.prank(testUser);
vm.expectRevert("!management");
termStrategy.setDiscountRateAdapter(address(valid));

vm.prank(management);
vm.expectRevert();
termStrategy.setDiscountRateAdapter(address(invalid));
Comment on lines +361 to +362
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Specify expected revert reason in vm.expectRevert()

In the test testSetDiscountRateAdapter, the vm.expectRevert() call before setting an invalid adapter address does not specify the expected revert reason or selector. For more precise testing, it's recommended to include the expected error message or error selector.

Apply this diff to specify the expected revert reason:

 vm.prank(management);
-vm.expectRevert();
+vm.expectRevert("InvalidTermAdapter(address)");
 termStrategy.setDiscountRateAdapter(address(invalid));

Replace "InvalidTermAdapter(address)" with the actual revert reason emitted by the setDiscountRateAdapter function when provided with an invalid address.

Committable suggestion was skipped due to low confidence.


vm.prank(management);
termStrategy.setDiscountRateAdapter(address(valid));
vm.stopPrank();

assertEq(address(valid), address(termStrategy.discountRateAdapter()));
}

function _getRepoTokenAmountGivenPurchaseTokenAmount(
uint256 purchaseTokenAmount,
MockTermRepoToken termRepoToken,
Expand Down
107 changes: 95 additions & 12 deletions src/test/TestUSDCOffers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ contract TestUSDCSubmitOffer is Setup {
// start with some initial funds
mockUSDC.mint(address(strategy), 100e6);

assertEq(termStrategy.liquidReserveRatio(), 1e18);

initialState.totalAssetValue = termStrategy.totalAssetValue();
initialState.totalLiquidBalance = termStrategy.totalLiquidBalance();
}
Expand Down Expand Up @@ -71,6 +73,22 @@ contract TestUSDCSubmitOffer is Setup {
assertEq(termStrategy.totalLiquidBalance(), initialState.totalLiquidBalance - 1e6);
// test: totalAssetValue = total liquid balance + pending offer amount
assertEq(termStrategy.totalAssetValue(), termStrategy.totalLiquidBalance() + 1e6);

assertEq(termStrategy.liquidReserveRatio(), 0.99e18);

uint256 repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);
}

function testSubmitOfferBelowLiquidReserveRatio() public {
vm.startPrank(management);
termStrategy.setRequiredReserveRatio(0.5e18);

vm.expectRevert(abi.encodeWithSelector(Strategy.BalanceBelowRequiredReserveRatio.selector));
termStrategy.submitAuctionOffer(
repoToken1WeekAuction, address(repoToken1Week), bytes32("offer id hash 1"), bytes32("test price"), 51e6
);

}

function testEditOffer() public {
Expand All @@ -80,16 +98,22 @@ contract TestUSDCSubmitOffer is Setup {
// TODO: fuzz this
uint256 offerAmount = 4e6;

assertEq(termStrategy.totalLiquidBalance(), initialState.totalLiquidBalance - 1e6);
uint256 repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);
assertEq(termStrategy.totalAssetValue(), termStrategy.totalLiquidBalance() + 1e6);
assertEq(termStrategy.liquidReserveRatio(), 0.99e18);

vm.prank(management);
bytes32[] memory offerIds = termStrategy.submitAuctionOffer(
repoToken1WeekAuction, address(repoToken1Week), idHash1, bytes32("test price"), offerAmount
repoToken1WeekAuction, address(repoToken1Week), offerId1, bytes32("test price"), offerAmount
);

uint256 offerDiff = offerAmount - 1e6;

assertEq(termStrategy.totalLiquidBalance(), initialState.totalLiquidBalance - offerDiff);
// test: totalAssetValue = total liquid balance + pending offer amount
assertEq(termStrategy.totalAssetValue(), termStrategy.totalLiquidBalance() + offerDiff);
assertEq(termStrategy.totalLiquidBalance(), initialState.totalLiquidBalance - offerAmount);
repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 4e6);
assertEq(termStrategy.totalAssetValue(), termStrategy.totalLiquidBalance() + offerAmount);
assertEq(termStrategy.liquidReserveRatio(), 0.96e18);
Comment on lines +159 to +166
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correcting Offer Editing Logic

Updating the submitAuctionOffer call to use offerId1 ensures that the existing offer is edited rather than creating a new one. The subsequent assertions validate that:

  • The total liquid balance reflects the new offer amount.
  • The repo token holding value is updated to the new offer amount.
  • The liquid reserve ratio adjusts accordingly.

This change fixes potential issues with offer identification during editing.

}

function testDeleteOffers() public {
Expand All @@ -107,6 +131,10 @@ contract TestUSDCSubmitOffer is Setup {

assertEq(termStrategy.totalLiquidBalance(), initialState.totalLiquidBalance);
assertEq(termStrategy.totalAssetValue(), termStrategy.totalLiquidBalance());
uint256 repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 0);
assertEq(termStrategy.liquidReserveRatio(), 1e18);

}

uint256 public constant THREESIXTY_DAYCOUNT_SECONDS = 360 days;
Expand Down Expand Up @@ -146,6 +174,10 @@ contract TestUSDCSubmitOffer is Setup {
);

repoToken1WeekAuction.auctionSuccess(offerIds, fillAmounts, repoTokenAmounts);
assertEq(termStrategy.liquidReserveRatio(), 0.99e18);

uint256 repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);

//console2.log("repoTokenAmounts[0]", repoTokenAmounts[0]);

Expand All @@ -158,6 +190,10 @@ contract TestUSDCSubmitOffer is Setup {
assertEq(holdings.length, 0);

termStrategy.auctionClosed();
assertEq(termStrategy.liquidReserveRatio(), 0.99e18);

repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);

// test: asset value should equal to initial asset value (liquid + repo tokens)
assertEq(termStrategy.totalAssetValue(), initialState.totalAssetValue);
Expand All @@ -175,6 +211,7 @@ contract TestUSDCSubmitOffer is Setup {

function testCompleteAuctionSuccessPartial() public {
bytes32 offerId1 = _submitOffer(bytes32("offer id 1"), 1e6);
assertEq(termStrategy.liquidReserveRatio(), 0.99e18);
uint256 fillAmount = 0.5e6;

bytes32[] memory offerIds = new bytes32[](1);
Expand All @@ -188,8 +225,16 @@ contract TestUSDCSubmitOffer is Setup {
fillAmount, repoToken1Week, TEST_REPO_TOKEN_RATE
);

uint256 repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);

repoToken1WeekAuction.auctionSuccess(offerIds, fillAmounts, repoTokenAmounts);

assertEq(termStrategy.liquidReserveRatio(), 0.995e18);

repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 0.5e6);

// test: asset value should equal to initial asset value (liquid + pending offers)
assertEq(termStrategy.totalAssetValue(), initialState.totalAssetValue);

Expand All @@ -200,6 +245,9 @@ contract TestUSDCSubmitOffer is Setup {

termStrategy.auctionClosed();

repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 0.5e6);

// test: asset value should equal to initial asset value (liquid + repo tokens)
assertEq(termStrategy.totalAssetValue(), initialState.totalAssetValue);

Expand All @@ -214,14 +262,49 @@ contract TestUSDCSubmitOffer is Setup {
assertEq(offers.length, 0);
}

function testCompleteAuctionCanceled() public {
function testAuctionCancelForWithdrawal() public {
bytes32 offerId1 = _submitOffer(bytes32("offer id hash 1"), 1e6);

repoToken1WeekAuction.auctionCanceled();
uint256 repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);

repoToken1WeekAuction.auctionCancelForWithdrawal();

repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);


// test: check value before calling complete auction
termStrategy.auctionClosed();

repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 0);

bytes32[] memory offers = termStrategy.pendingOffers();

assertEq(offers.length, 0);
}

function testAuctionCancel() public {
bytes32 offerId1 = _submitOffer(bytes32("offer id hash 1"), 1e6);

uint256 repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 1e6);

bytes32[] memory offerIds = new bytes32[](1);
offerIds[0] = offerId1;

repoToken1WeekAuction.auctionCancel(offerIds);

repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 0);

// test: check value before calling complete auction
termStrategy.auctionClosed();

repoTokenHoldingValue = termStrategy.getRepoTokenHoldingValue(address(repoToken1Week));
assertEq(repoTokenHoldingValue, 0);

bytes32[] memory offers = termStrategy.pendingOffers();

assertEq(offers.length, 0);
Expand All @@ -238,8 +321,8 @@ contract TestUSDCSubmitOffer is Setup {
bytes32[] memory offers = termStrategy.pendingOffers();

assertEq(offers.length, 2);
assertEq(offers[0], offerId2);
assertEq(offers[1], offerId1);
assertEq(offers[0], offerId1);
assertEq(offers[1], offerId2);
}

function testMultipleOffersFillAndNoFill() public {
Expand Down Expand Up @@ -274,7 +357,7 @@ contract TestUSDCSubmitOffer is Setup {

assertEq(termStrategy.totalLiquidBalance(), 50e6);

_submitOffer(idHash1, 100e6);
_submitOffer(offerId1, 100e6);

assertEq(termStrategy.totalLiquidBalance(), 0);
}
Comment on lines +425 to 428
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing Revert Expectation for Insufficient Liquidity

In testEditOfferTotalGreaterThanCurrentLiquidity, when editing the offer to 100e6, the total liquid balance is reduced to zero without handling insufficient liquidity.

Consider adding an expectation for a revert due to insufficient liquidity:

 vm.prank(management);
+vm.expectRevert(abi.encodeWithSelector(Strategy.InsufficientLiquidBalance.selector, 50e6, 100e6));
 bytes32[] memory offerIds = termStrategy.submitAuctionOffer(
     repoToken1WeekAuction, address(repoToken1Week), offerId1, bytes32("test price"), 100e6
 );

This ensures the test correctly handles scenarios where liquidity is not sufficient to support the increased offer amount.

Committable suggestion was skipped due to low confidence.

Expand All @@ -285,7 +368,7 @@ contract TestUSDCSubmitOffer is Setup {

assertEq(termStrategy.totalLiquidBalance(), 0);

_submitOffer(idHash1, 50e6);
_submitOffer(offerId1, 50e6);

assertEq(termStrategy.totalLiquidBalance(), 50e6);
}
Expand Down
Loading