Skip to content

Commit 5ea333b

Browse files
committed
unit test for lend and unlend, expose abi
1 parent 7cbecfa commit 5ea333b

File tree

4 files changed

+109
-4
lines changed

4 files changed

+109
-4
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ docs/
1818
.idea
1919
cache
2020
lib
21-
lib/chainlink-local
21+
lib/chainlink-local
22+
!out/CrossCredit.sol

src/CrossCredit.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ contract CrossCredit is Ownable, ReentrancyGuard, CCIPReceiver, ICrossCredit {
192192
uint256 userTotalBorrowUSDValue = getTotalUSDValueOfUserByType(msg.sender, 2);
193193

194194
(int256 price, uint8 priceFeedDecimals) = _getAssetPriceData(_asset);
195-
uint256 currentUnlendAmountUSD = (_amount * uint256(price)) / (10 ** priceFeedDecimals);
195+
196+
uint8 localAssetDecimals = s_assetDecimals[_asset];
197+
198+
uint256 currentUnlendAmountUSD = (_amount * uint256(price)) / (10 ** localAssetDecimals);
196199

197200
if (userTotalLendUSDValue < currentUnlendAmountUSD) revert Error.InsufficientCollateralRemaining();
198201

test/CrossCreditBorrow.t.sol

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ contract CrossCreditBorrow is Base {
88
function test_lendOnSourceAndBorrowOnDest() public {
99
_setOraclePrices(1);
1010

11-
uint256 amountToLend = 1e6; // 1 USDC
11+
uint256 amountToLend = 1e6; // ~1 USDC
1212
address assetToLend = address(sourceUSDC);
1313

1414
// --- SOURCE CHAIN ACTIONS (Lend) ---
@@ -52,7 +52,7 @@ contract CrossCreditBorrow is Base {
5252

5353
// Calculate max borrowable amount and the specific amount to borrow
5454
(,int usdPriceETH_dest, , ,) = priceFeedOnDestETH.latestRoundData();
55-
uint256 LTV = crossCreditOnDest.LTV(); // Assuming LTV is 80 (0.8)
55+
uint256 LTV = crossCreditOnDest.LTV();
5656
uint256 maxBorrowableUSD = (LTV * userTotalLendValue) / 100;
5757
uint256 targetBorrowUSD = ((LTV - 10) * userTotalLendValue) / 100; // Borrow 10% less than max for safety
5858

@@ -99,4 +99,62 @@ contract CrossCreditBorrow is Base {
9999
assertEq(userTotalBorrowValueOnDest, userTotalBorrowValueOnSource, "Final Borrow USD value mismatch between chains");
100100
}
101101

102+
function test_lendOnSourceBorrowAndRepayOnDest() public {
103+
_setOraclePrices(1);
104+
105+
uint256 amountToLend = 1e6; // ~1 USDC
106+
address assetToLend = address(sourceUSDC);
107+
108+
vm.selectFork(sourceFork);
109+
110+
vm.startPrank(firstUser);
111+
sourceUSDC.approve(address(crossCreditOnSource), amountToLend);
112+
crossCreditOnSource.lend(amountToLend, assetToLend);
113+
vm.stopPrank();
114+
115+
ccipLocalSimulatorFork.switchChainAndRouteMessage(destinationFork);
116+
117+
vm.selectFork(destinationFork);
118+
uint userTotalLendValue = crossCreditOnDest.getTotalUSDValueOfUserByType(firstUser, 1);
119+
(,int usdPriceETH_dest, , ,) = priceFeedOnDestETH.latestRoundData();
120+
uint256 LTV = crossCreditOnDest.LTV();
121+
uint256 maxBorrowableUSD = (LTV * userTotalLendValue) / 100;
122+
uint256 targetBorrowUSD = ((LTV - 10) * userTotalLendValue) / 100; // Borrow 10% less than max for safety
123+
124+
uint256 nativeAssetDecimals = crossCreditOnDest.getAssetDecimalsOnSource(NATIVE_ASSET);
125+
uint256 amountToBorrowRaw = (targetBorrowUSD * (10 ** nativeAssetDecimals)) / uint256(usdPriceETH_dest);
126+
127+
vm.startPrank(firstUser);
128+
// BORROW
129+
uint userBalOnDestBefore = firstUser.balance;
130+
crossCreditOnDest.borrow(amountToBorrowRaw, NATIVE_ASSET);
131+
uint userBalOnDestAfter = firstUser.balance;
132+
vm.stopPrank();
133+
134+
ccipLocalSimulatorFork.switchChainAndRouteMessage(sourceFork);
135+
136+
vm.selectFork(destinationFork);
137+
// REPAY
138+
vm.startPrank(firstUser);
139+
uint userTotalBorrowValue = crossCreditOnDest.getTotalUSDValueOfUserByType(firstUser, 2);
140+
bool usdValCalc = userTotalBorrowValue < targetBorrowUSD ? targetBorrowUSD - userTotalBorrowValue < 10 : userTotalBorrowValue - targetBorrowUSD < 10;
141+
assertEq(usdValCalc, true, "Borrowed USD value not within tolerance of target");
142+
143+
_setOraclePrices(1); // Price change
144+
(,usdPriceETH_dest, , ,) = priceFeedOnDestETH.latestRoundData();
145+
uint amountToRepay = (userTotalBorrowValue * (10 ** nativeAssetDecimals)) / uint256(usdPriceETH_dest);
146+
vm.deal(firstUser, amountToRepay);
147+
crossCreditOnDest.repay{value: amountToRepay}(amountToRepay, NATIVE_ASSET);
148+
userTotalBorrowValue = crossCreditOnDest.getTotalUSDValueOfUserByType(firstUser, 2);
149+
150+
bool userBorrowValueRepaid = userTotalBorrowValue == 0 || userTotalBorrowValue < 10;
151+
assertTrue(userBorrowValueRepaid, "Loan repayment not within range");
152+
vm.stopPrank();
153+
ccipLocalSimulatorFork.switchChainAndRouteMessage(sourceFork);
154+
155+
vm.selectFork(sourceFork);
156+
userTotalBorrowValue = crossCreditOnSource.getTotalUSDValueOfUserByType(firstUser, 2);
157+
userBorrowValueRepaid = userTotalBorrowValue == 0 || userTotalBorrowValue < 10;
158+
assertTrue(userBorrowValueRepaid, "Loan repayment not within range");
159+
}
102160
}

test/CrossCreditLend.t.sol

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
import {Base} from "./Base.t.sol";
5+
import {console} from "forge-std/console.sol";
6+
7+
8+
contract CrossCreditLend is Base {
9+
function test_lendAndUnlend() public {
10+
_setOraclePrices(1);
11+
12+
uint256 amountToLend = 1e6; // ~1 USDC
13+
address assetToLend = address(sourceUSDC);
14+
15+
vm.selectFork(sourceFork);
16+
17+
vm.startPrank(firstUser);
18+
sourceUSDC.approve(address(crossCreditOnSource), amountToLend);
19+
crossCreditOnSource.lend(amountToLend, assetToLend);
20+
vm.stopPrank();
21+
22+
ccipLocalSimulatorFork.switchChainAndRouteMessage(destinationFork);
23+
24+
vm.selectFork(sourceFork);
25+
vm.startPrank(firstUser);
26+
uint userLendUSDValue = crossCreditOnSource.getTotalUSDValueOfUserByType(firstUser, 1);
27+
console.log("User lend usd val before unlend: ", userLendUSDValue);
28+
uint userBalBeforeUnlend = sourceUSDC.balanceOf(firstUser);
29+
crossCreditOnSource.unlend(amountToLend, assetToLend);
30+
uint userBalAfterUnlend = sourceUSDC.balanceOf(firstUser);
31+
userLendUSDValue = crossCreditOnSource.getTotalUSDValueOfUserByType(firstUser, 1);
32+
33+
assertEq(userLendUSDValue, 0, "User Lend Value mismatch");
34+
assertEq(userBalAfterUnlend, userBalBeforeUnlend + amountToLend, "User balance mismatch");
35+
vm.stopPrank();
36+
ccipLocalSimulatorFork.switchChainAndRouteMessage(destinationFork);
37+
38+
vm.selectFork(destinationFork);
39+
userLendUSDValue = crossCreditOnDest.getTotalUSDValueOfUserByType(firstUser, 1);
40+
assertEq(userLendUSDValue, 0, "User Lend Value mismatch");
41+
42+
}
43+
}

0 commit comments

Comments
 (0)