Skip to content

Commit da512a3

Browse files
committed
fix: price change, tests
1 parent 6141f43 commit da512a3

6 files changed

Lines changed: 105 additions & 34 deletions

File tree

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,19 @@ For this challenge we will not focus on the Lending aspect as much as the other
198198

199199
🎉 Excellent! Re-deploy your contract with `yarn deploy --reset`. We want to do a fresh deploy of all the contracts so that they each have correct constructor parameters. Now try out your methods from the front end and see if you need to make any changes.
200200

201+
<Tabs>
202+
<Tab label="Hardhat">
203+
204+
> 🧪 Run the tests for this checkpoint: `yarn test --grep "Collateral Operations"`
205+
206+
</Tab>
207+
<Tab label="Foundry">
208+
209+
> 🧪 Run the tests for this checkpoint: `yarn test --match-test "test_Collateral_"`
210+
211+
</Tab>
212+
</Tabs>
213+
201214
💰 Don't forget to give yourself some ETH from the faucet!
202215

203216
![faucet](https://github.com/user-attachments/assets/e8b8ac20-19fa-45d4-bc5a-8049ac04487e)
@@ -337,6 +350,19 @@ For this challenge we will not focus on the Lending aspect as much as the other
337350

338351
🔄 Run `yarn deploy --reset` so you can play with borrowing and repaying on the front end. You can adjust the price of CORN by pressing the + and - buttons under CORN price in the top right corner. See how your open position's collateral value shifts as the price moves.
339352

353+
<Tabs>
354+
<Tab label="Hardhat">
355+
356+
> 🧪 Run the tests for this checkpoint: `yarn test --grep "Borrowing Operations|Repayment Operations"`
357+
358+
</Tab>
359+
<Tab label="Foundry">
360+
361+
> 🧪 Run the tests for this checkpoint: `yarn test --match-test "test_(Borrowing|Repayment)_"`
362+
363+
</Tab>
364+
</Tabs>
365+
340366
<details><summary>Solution Code</summary>
341367

342368
```solidity
@@ -451,6 +477,19 @@ For this challenge we will not focus on the Lending aspect as much as the other
451477

452478
🔄 You know the drill. Run `yarn deploy --reset` so you can try liquidating on the front end. It may be useful to open a private browser tab and go to `localhost:3000` so you can simulate multiple accounts. You can also borrow and then switch wallets and use the swap button in the CORN wallet (on the right side of the screen) to acquire some CORN. Now adjust the price using the price controls in the CORN price module and liquidate the borrower.
453479

480+
<Tabs>
481+
<Tab label="Hardhat">
482+
483+
> 🧪 Run the tests for this checkpoint: `yarn test --grep "Liquidation"`
484+
485+
</Tab>
486+
<Tab label="Foundry">
487+
488+
> 🧪 Run the tests for this checkpoint: `yarn test --match-test "test_Liquidation_"`
489+
490+
</Tab>
491+
</Tabs>
492+
454493
🫴 Notice how the borrower still has their borrowed CORN after they get liquidated. They get to keep their CORN since the liquidator paid their CORN debt back to the protocol on their behalf.
455494

456495
---
@@ -466,6 +505,19 @@ For this challenge we will not focus on the Lending aspect as much as the other
466505

467506
🔙 Throwback to the `withdrawCollateral` function. What happens when a borrower withdraws collateral exceeding the safe position ratio? You should add a `_validatePosition` check to make sure that never happens. You should add it after the `s_userCollateral` mapping is updated so that it is checking the final state instead of the current state. Skip the check if they don't have any borrowed CORN.
468507

508+
<Tabs>
509+
<Tab label="Hardhat">
510+
511+
> 🧪 Run the tests for this checkpoint: `yarn test --grep "should prevent withdrawing collateral if it makes the position liquidatable"`
512+
513+
</Tab>
514+
<Tab label="Foundry">
515+
516+
> 🧪 Run the tests for this checkpoint: `yarn test --match-test "test_Withdraw_"`
517+
518+
</Tab>
519+
</Tabs>
520+
469521
🎉 Great work! Your contract has all the necessary functionality to help people get CORN loans.
470522

471523
🍨 Now you get to see something real special. Run `yarn deploy --reset` as you usually do. Then run:

extension/.ai/CHALLENGE.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ checkpoints:
135135
foundry: "packages/foundry/contracts/Lending.sol"
136136
test:
137137
hardhat: "yarn test --grep 'Collateral Operations'"
138-
foundry: "yarn test --match-test 'Checkpoint1'"
138+
foundry: "yarn test --match-test 'test_Collateral_'"
139139
hints:
140140
- "For `addCollateral`: it's just `s_userCollateral[msg.sender] += msg.value` after the validation check."
141141
- |
@@ -253,7 +253,7 @@ checkpoints:
253253
foundry: "packages/foundry/contracts/Lending.sol"
254254
test:
255255
hardhat: "yarn test --grep 'Collateral Operations'"
256-
foundry: "yarn test --match-test 'Checkpoint1'"
256+
foundry: "yarn test --match-test 'test_Collateral_'"
257257
hints:
258258
- "`calculateCollateralValue` is a one-liner: `return (s_userCollateral[user] * i_cornDEX.currentPrice()) / 1e18;`"
259259
- |
@@ -397,7 +397,7 @@ checkpoints:
397397
foundry: "packages/foundry/contracts/Lending.sol"
398398
test:
399399
hardhat: "yarn test --grep 'Borrowing Operations|Repayment Operations|Collateral Operations'"
400-
foundry: "yarn test --match-test 'Checkpoint3'"
400+
foundry: "yarn test --match-test 'test_(Borrowing|Repayment|Withdraw)_'"
401401
hints:
402402
- "For `borrowCorn`: update mapping first, validate, then transfer. The order matters — `_validatePosition` checks the new state."
403403
- |
@@ -536,7 +536,7 @@ checkpoints:
536536
foundry: "packages/foundry/contracts/Lending.sol"
537537
test:
538538
hardhat: "yarn test --grep 'Liquidation'"
539-
foundry: "yarn test --match-test 'Checkpoint4'"
539+
foundry: "yarn test --match-test 'test_Liquidation_'"
540540
hints:
541541
- "Check `isLiquidatable(user)` first. Then verify `i_corn.balanceOf(msg.sender) >= userDebt`. Use `transferFrom` to pull the CORN from the liquidator."
542542
- |

extension/README.md.args.mjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ For this challenge we will not focus on the Lending aspect as much as the other
168168
169169
🎉 Excellent! Re-deploy your contract with \`yarn deploy --reset\`. We want to do a fresh deploy of all the contracts so that they each have correct constructor parameters. Now try out your methods from the front end and see if you need to make any changes.
170170
171+
> 🧪 Run the tests for this checkpoint: \`${solidityFramework === "hardhat" ? `yarn test --grep "Collateral Operations"` : `yarn test --match-test "test_Collateral_"`}\`
172+
171173
💰 Don't forget to give yourself some ETH from the faucet!
172174
173175
![faucet](https://github.com/user-attachments/assets/e8b8ac20-19fa-45d4-bc5a-8049ac04487e)
@@ -296,6 +298,8 @@ ${solidityFramework === "hardhat" ? `> 💡 Since we added all those complex hel
296298
297299
🔄 Run \`yarn deploy --reset\` so you can play with borrowing and repaying on the front end. You can adjust the price of CORN by pressing the + and - buttons under CORN price in the top right corner. See how your open position's collateral value shifts as the price moves.
298300
301+
> 🧪 Run the tests for this checkpoint: \`${solidityFramework === "hardhat" ? `yarn test --grep "Borrowing Operations|Repayment Operations"` : `yarn test --match-test "test_(Borrowing|Repayment)_"`}\`
302+
299303
<details><summary>Solution Code</summary>
300304
301305
\`\`\`solidity
@@ -409,6 +413,8 @@ ${solidityFramework === "hardhat" ? `> 💡 Since we added all those complex hel
409413
410414
🔄 You know the drill. Run \`yarn deploy --reset\` so you can try liquidating on the front end. It may be useful to open a private browser tab and go to \`localhost:3000\` so you can simulate multiple accounts. You can also borrow and then switch wallets and use the swap button in the CORN wallet (on the right side of the screen) to acquire some CORN. Now adjust the price using the price controls in the CORN price module and liquidate the borrower.
411415
416+
> 🧪 Run the tests for this checkpoint: \`${solidityFramework === "hardhat" ? `yarn test --grep "Liquidation"` : `yarn test --match-test "test_Liquidation_"`}\`
417+
412418
🫴 Notice how the borrower still has their borrowed CORN after they get liquidated. They get to keep their CORN since the liquidator paid their CORN debt back to the protocol on their behalf.
413419
414420
---
@@ -424,6 +430,8 @@ ${solidityFramework === "hardhat" ? `> 💡 Since we added all those complex hel
424430
425431
🔙 Throwback to the \`withdrawCollateral\` function. What happens when a borrower withdraws collateral exceeding the safe position ratio? You should add a \`_validatePosition\` check to make sure that never happens. You should add it after the \`s_userCollateral\` mapping is updated so that it is checking the final state instead of the current state. Skip the check if they don't have any borrowed CORN.
426432
433+
> 🧪 Run the tests for this checkpoint: \`${solidityFramework === "hardhat" ? `yarn test --grep "should prevent withdrawing collateral if it makes the position liquidatable"` : `yarn test --match-test "test_Withdraw_"`}\`
434+
427435
🎉 Great work! Your contract has all the necessary functionality to help people get CORN loans.
428436
429437
🍨 Now you get to see something real special. Run \`yarn deploy --reset\` as you usually do. Then run:

extension/packages/foundry/script/DeployLending.s.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ contract DeployLending is ScaffoldETHDeploy {
2626
corn.mintTo(deployer, 1_000_000 ether);
2727

2828
// Give ETH and CORN to MovePrice contract for price manipulation testing
29-
vm.deal(address(movePrice), 5000 ether);
29+
// (vm.deal is a cheatcode and doesn't broadcast to the live node, so use a real transfer)
30+
(bool sent,) = address(movePrice).call{value: 5000 ether}("");
31+
require(sent, "Failed to fund MovePrice");
3032
corn.mintTo(address(movePrice), 5_000_000 ether);
3133

3234
// Mint CORN to lending contract for borrowers

extension/packages/foundry/test/Lending.t.sol

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,22 @@ contract LendingTest is Test {
4848
}
4949

5050
// ============================================================
51-
// Checkpoint 1: Collateral Operations
51+
// Collateral Operations
5252
// ============================================================
5353

54-
function test_Checkpoint1_AllowAddingCollateral() public {
54+
function test_Collateral_AllowAddingCollateral() public {
5555
vm.prank(user1);
5656
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
5757
assertEq(lending.s_userCollateral(user1), COLLATERAL_AMOUNT);
5858
}
5959

60-
function test_Checkpoint1_RequireNonZeroValue() public {
60+
function test_Collateral_RequireNonZeroValue() public {
6161
vm.prank(user1);
6262
vm.expectRevert(abi.encodeWithSelector(bytes4(keccak256("Lending__InvalidAmount()"))));
6363
lending.addCollateral{ value: 0 }();
6464
}
6565

66-
function test_Checkpoint1_EmitCollateralAddedEvent() public {
66+
function test_Collateral_EmitCollateralAddedEvent() public {
6767
vm.prank(user1);
6868
vm.recordLogs();
6969
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
@@ -78,7 +78,7 @@ contract LendingTest is Test {
7878
assertTrue(found, "CollateralAdded event should be emitted");
7979
}
8080

81-
function test_Checkpoint1_AllowWithdrawingWhenNoDebt() public {
81+
function test_Collateral_AllowWithdrawingWhenNoDebt() public {
8282
vm.startPrank(user1);
8383
uint256 balanceInitial = user1.balance;
8484
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
@@ -93,7 +93,7 @@ contract LendingTest is Test {
9393
vm.stopPrank();
9494
}
9595

96-
function test_Checkpoint1_PreventWithdrawingMoreThanDeposited() public {
96+
function test_Collateral_PreventWithdrawingMoreThanDeposited() public {
9797
vm.startPrank(user1);
9898
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
9999

@@ -102,7 +102,7 @@ contract LendingTest is Test {
102102
vm.stopPrank();
103103
}
104104

105-
function test_Checkpoint1_PreventWithdrawingZero() public {
105+
function test_Collateral_PreventWithdrawingZero() public {
106106
vm.startPrank(user1);
107107
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
108108

@@ -111,7 +111,11 @@ contract LendingTest is Test {
111111
vm.stopPrank();
112112
}
113113

114-
function test_Checkpoint3_PreventWithdrawIfMakesLiquidatable() public {
114+
// ============================================================
115+
// Withdraw Protection
116+
// ============================================================
117+
118+
function test_Withdraw_PreventIfMakesLiquidatable() public {
115119
vm.startPrank(user1);
116120
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
117121
lending.borrowCorn(BORROW_AMOUNT);
@@ -122,10 +126,10 @@ contract LendingTest is Test {
122126
}
123127

124128
// ============================================================
125-
// Checkpoint 3: Borrowing Operations
129+
// Borrowing Operations
126130
// ============================================================
127131

128-
function test_Checkpoint3_AllowWhenSufficientlyCollateralized() public {
132+
function test_Borrowing_AllowWhenSufficientlyCollateralized() public {
129133
vm.startPrank(user1);
130134
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
131135

@@ -136,7 +140,7 @@ contract LendingTest is Test {
136140
vm.stopPrank();
137141
}
138142

139-
function test_Checkpoint3_PreventWhenInsufficientlyCollateralized() public {
143+
function test_Borrowing_PreventWhenInsufficientlyCollateralized() public {
140144
vm.startPrank(user1);
141145
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
142146

@@ -146,7 +150,7 @@ contract LendingTest is Test {
146150
vm.stopPrank();
147151
}
148152

149-
function test_Checkpoint3_PreventZeroBorrowAmount() public {
153+
function test_Borrowing_PreventZeroBorrowAmount() public {
150154
vm.startPrank(user1);
151155
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
152156

@@ -155,7 +159,7 @@ contract LendingTest is Test {
155159
vm.stopPrank();
156160
}
157161

158-
function test_Checkpoint3_EmitAssetBorrowedEvent() public {
162+
function test_Borrowing_EmitAssetBorrowedEvent() public {
159163
vm.startPrank(user1);
160164
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
161165

@@ -174,10 +178,10 @@ contract LendingTest is Test {
174178
}
175179

176180
// ============================================================
177-
// Checkpoint 3: Repayment Operations
181+
// Repayment Operations
178182
// ============================================================
179183

180-
function test_Checkpoint3_AllowRepayingFullAmount() public {
184+
function test_Repayment_AllowRepayingFullAmount() public {
181185
vm.startPrank(user1);
182186
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
183187
lending.borrowCorn(BORROW_AMOUNT);
@@ -188,7 +192,7 @@ contract LendingTest is Test {
188192
vm.stopPrank();
189193
}
190194

191-
function test_Checkpoint3_AllowPartialRepayment() public {
195+
function test_Repayment_AllowPartialRepayment() public {
192196
vm.startPrank(user1);
193197
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
194198
lending.borrowCorn(BORROW_AMOUNT);
@@ -199,7 +203,7 @@ contract LendingTest is Test {
199203
vm.stopPrank();
200204
}
201205

202-
function test_Checkpoint3_PreventRepayingMoreThanBorrowed() public {
206+
function test_Repayment_PreventRepayingMoreThanBorrowed() public {
203207
vm.startPrank(user1);
204208
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
205209
lending.borrowCorn(BORROW_AMOUNT);
@@ -210,7 +214,7 @@ contract LendingTest is Test {
210214
vm.stopPrank();
211215
}
212216

213-
function test_Checkpoint3_PreventZeroRepayment() public {
217+
function test_Repayment_PreventZeroRepayment() public {
214218
vm.startPrank(user1);
215219
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
216220
lending.borrowCorn(BORROW_AMOUNT);
@@ -220,7 +224,7 @@ contract LendingTest is Test {
220224
vm.stopPrank();
221225
}
222226

223-
function test_Checkpoint3_EmitAssetRepaidEvent() public {
227+
function test_Repayment_EmitAssetRepaidEvent() public {
224228
vm.startPrank(user1);
225229
lending.addCollateral{ value: COLLATERAL_AMOUNT }();
226230
lending.borrowCorn(BORROW_AMOUNT);
@@ -241,7 +245,7 @@ contract LendingTest is Test {
241245
}
242246

243247
// ============================================================
244-
// Checkpoint 4: Liquidation
248+
// Liquidation
245249
// ============================================================
246250

247251
function _setupLiquidation() internal {
@@ -256,7 +260,7 @@ contract LendingTest is Test {
256260
cornToken.approve(address(lending), BORROW_AMOUNT);
257261
}
258262

259-
function test_Checkpoint4_AllowWhenPositionUnsafe() public {
263+
function test_Liquidation_AllowWhenPositionUnsafe() public {
260264
_setupLiquidation();
261265

262266
// Drop price of ETH by swapping a large amount
@@ -275,7 +279,7 @@ contract LendingTest is Test {
275279
assertTrue(afterBalance > beforeBalance);
276280
}
277281

278-
function test_Checkpoint4_PreventOnSafePositions() public {
282+
function test_Liquidation_PreventOnSafePositions() public {
279283
_setupLiquidation();
280284

281285
assertFalse(lending.isLiquidatable(user1));
@@ -285,7 +289,7 @@ contract LendingTest is Test {
285289
lending.liquidate(user1);
286290
}
287291

288-
function test_Checkpoint4_RequireEnoughCorn() public {
292+
function test_Liquidation_RequireEnoughCorn() public {
289293
_setupLiquidation();
290294

291295
// Drop price
@@ -304,7 +308,7 @@ contract LendingTest is Test {
304308
lending.liquidate(user1);
305309
}
306310

307-
function test_Checkpoint4_EmitEvent() public {
311+
function test_Liquidation_EmitEvent() public {
308312
_setupLiquidation();
309313

310314
// Drop price
@@ -326,5 +330,5 @@ contract LendingTest is Test {
326330
assertTrue(found, "Liquidation event should be emitted");
327331
}
328332

329-
receive() external payable {}
333+
receive() external payable { }
330334
}

0 commit comments

Comments
 (0)