@rev-net/core-v6 0.0.29 → 0.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/ADMINISTRATION.md +19 -9
  2. package/ARCHITECTURE.md +3 -0
  3. package/AUDIT_INSTRUCTIONS.md +11 -1
  4. package/CHANGELOG.md +26 -0
  5. package/README.md +1 -0
  6. package/RISKS.md +28 -4
  7. package/SKILLS.md +2 -1
  8. package/USER_JOURNEYS.md +17 -3
  9. package/package.json +2 -2
  10. package/references/operations.md +1 -1
  11. package/script/Deploy.s.sol +25 -6
  12. package/src/REVHiddenTokens.sol +149 -0
  13. package/src/REVLoans.sol +115 -144
  14. package/src/REVOwner.sol +11 -3
  15. package/src/interfaces/IREVHiddenTokens.sol +53 -0
  16. package/src/interfaces/IREVLoans.sol +3 -6
  17. package/test/REV.integrations.t.sol +2 -1
  18. package/test/REVAutoIssuanceFuzz.t.sol +2 -1
  19. package/test/REVDeployerRegressions.t.sol +2 -2
  20. package/test/REVInvincibility.t.sol +6 -6
  21. package/test/REVInvincibilityHandler.sol +1 -1
  22. package/test/REVLifecycle.t.sol +2 -2
  23. package/test/REVLoans.invariants.t.sol +3 -3
  24. package/test/REVLoansAttacks.t.sol +7 -6
  25. package/test/REVLoansFeeRecovery.t.sol +12 -12
  26. package/test/REVLoansFindings.t.sol +4 -4
  27. package/test/REVLoansRegressions.t.sol +3 -3
  28. package/test/REVLoansSourceFeeRecovery.t.sol +4 -4
  29. package/test/REVLoansSourced.t.sol +48 -24
  30. package/test/REVLoansUnSourced.t.sol +3 -3
  31. package/test/TestBurnHeldTokens.t.sol +2 -2
  32. package/test/TestCEIPattern.t.sol +7 -6
  33. package/test/TestCashOutCallerValidation.t.sol +2 -2
  34. package/test/TestConversionDocumentation.t.sol +2 -2
  35. package/test/TestCrossCurrencyReclaim.t.sol +2 -2
  36. package/test/TestCrossSourceReallocation.t.sol +3 -3
  37. package/test/TestERC2771MetaTx.t.sol +6 -4
  38. package/test/TestEmptyBuybackSpecs.t.sol +2 -2
  39. package/test/TestFlashLoanSurplus.t.sol +3 -3
  40. package/test/TestHiddenTokens.t.sol +420 -0
  41. package/test/TestHookArrayOOB.t.sol +2 -2
  42. package/test/TestLiquidationBehavior.t.sol +4 -4
  43. package/test/TestLoanSourceRotation.t.sol +8 -6
  44. package/test/TestLoansCashOutDelay.t.sol +6 -6
  45. package/test/TestLongTailEconomics.t.sol +2 -2
  46. package/test/TestLowFindings.t.sol +13 -8
  47. package/test/TestMixedFixes.t.sol +7 -7
  48. package/test/TestPermit2Signatures.t.sol +3 -3
  49. package/test/TestReallocationSandwich.t.sol +4 -3
  50. package/test/TestRevnetRegressions.t.sol +3 -4
  51. package/test/TestSplitWeightAdjustment.t.sol +4 -3
  52. package/test/TestSplitWeightE2E.t.sol +4 -3
  53. package/test/TestSplitWeightFork.t.sol +2 -2
  54. package/test/TestStageTransitionBorrowable.t.sol +2 -2
  55. package/test/TestSwapTerminalPermission.t.sol +2 -2
  56. package/test/TestUint112Overflow.t.sol +3 -3
  57. package/test/TestZeroAmountLoanGuard.t.sol +3 -3
  58. package/test/TestZeroRepayment.t.sol +3 -3
  59. package/test/audit/LoanIdOverflowGuard.t.sol +4 -4
  60. package/test/audit/NemesisOperatorDelegation.t.sol +278 -0
  61. package/test/fork/ForkTestBase.sol +4 -3
  62. package/test/fork/TestLoanBorrowFork.t.sol +2 -1
  63. package/test/fork/TestLoanERC20Fork.t.sol +4 -2
  64. package/test/fork/TestLoanTransferFork.t.sol +12 -2
  65. package/test/helpers/MaliciousContracts.sol +1 -1
  66. package/test/regression/TestBurnPermissionRequired.t.sol +4 -4
  67. package/test/regression/TestCashOutBuybackFeeLeak.t.sol +2 -2
  68. package/test/regression/TestCrossRevnetLiquidation.t.sol +2 -2
  69. package/test/regression/TestCumulativeLoanCounter.t.sol +3 -3
  70. package/test/regression/TestLiquidateGapHandling.t.sol +3 -3
  71. package/test/regression/TestZeroPriceFeed.t.sol +5 -5
@@ -0,0 +1,53 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
5
+
6
+ /// @notice Manages hiding (burning) and revealing (re-minting) revnet tokens to exclude them from totalSupply.
7
+ interface IREVHiddenTokens {
8
+ /// @notice Emitted when tokens are hidden (burned and tracked for later reveal).
9
+ /// @param revnetId The ID of the revnet whose tokens are hidden.
10
+ /// @param tokenCount The number of tokens hidden.
11
+ /// @param holder The address whose tokens are hidden.
12
+ /// @param caller The address that hid the tokens.
13
+ event HideTokens(uint256 indexed revnetId, uint256 tokenCount, address holder, address caller);
14
+
15
+ /// @notice Emitted when previously hidden tokens are revealed (re-minted).
16
+ /// @param revnetId The ID of the revnet whose tokens are revealed.
17
+ /// @param tokenCount The number of tokens revealed.
18
+ /// @param beneficiary The address receiving the revealed tokens.
19
+ /// @param holder The address whose hidden balance is decremented.
20
+ /// @param caller The address that revealed the tokens.
21
+ event RevealTokens(
22
+ uint256 indexed revnetId, uint256 tokenCount, address beneficiary, address holder, address caller
23
+ );
24
+
25
+ /// @notice The controller that manages revnets using this contract.
26
+ /// @return The controller contract.
27
+ function CONTROLLER() external view returns (IJBController);
28
+
29
+ /// @notice The number of tokens a holder has hidden for a given revnet.
30
+ /// @param holder The address of the token holder.
31
+ /// @param revnetId The ID of the revnet.
32
+ /// @return The number of hidden tokens.
33
+ function hiddenBalanceOf(address holder, uint256 revnetId) external view returns (uint256);
34
+
35
+ /// @notice The total number of hidden tokens for a revnet.
36
+ /// @param revnetId The ID of the revnet.
37
+ /// @return The total hidden token count.
38
+ function totalHiddenOf(uint256 revnetId) external view returns (uint256);
39
+
40
+ /// @notice Hide tokens by burning them and tracking them for later reveal.
41
+ /// @dev The holder must have granted BURN_TOKENS permission to this contract.
42
+ /// @param revnetId The ID of the revnet whose tokens to hide.
43
+ /// @param tokenCount The number of tokens to hide.
44
+ /// @param holder The address whose tokens to hide.
45
+ function hideTokensOf(uint256 revnetId, uint256 tokenCount, address holder) external;
46
+
47
+ /// @notice Reveal previously hidden tokens by re-minting them.
48
+ /// @param revnetId The ID of the revnet whose tokens to reveal.
49
+ /// @param tokenCount The number of tokens to reveal.
50
+ /// @param beneficiary The address that will receive the revealed tokens.
51
+ /// @param holder The address whose hidden balance to decrement.
52
+ function revealTokensOf(uint256 revnetId, uint256 tokenCount, address beneficiary, address holder) external;
53
+ }
@@ -5,7 +5,6 @@ import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol
5
5
  import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
6
6
  import {IJBPayoutTerminal} from "@bananapus/core-v6/src/interfaces/IJBPayoutTerminal.sol";
7
7
  import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
8
- import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
9
8
  import {IJBTokenUriResolver} from "@bananapus/core-v6/src/interfaces/IJBTokenUriResolver.sol";
10
9
  import {JBSingleAllowance} from "@bananapus/core-v6/src/structs/JBSingleAllowance.sol";
11
10
  import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
@@ -164,10 +163,6 @@ interface IREVLoans {
164
163
  /// @return The prices contract.
165
164
  function PRICES() external view returns (IJBPrices);
166
165
 
167
- /// @notice The contract that mints ERC-721s representing project ownership.
168
- /// @return The projects contract.
169
- function PROJECTS() external view returns (IJBProjects);
170
-
171
166
  /// @notice The ID of the REV revnet that receives protocol fees from loans.
172
167
  /// @return The REV revnet ID.
173
168
  function REV_ID() external view returns (uint256);
@@ -219,6 +214,7 @@ interface IREVLoans {
219
214
  /// @param collateralCount The amount of tokens to use as collateral for the loan.
220
215
  /// @param beneficiary The address that will receive the borrowed funds and fee payment tokens.
221
216
  /// @param prepaidFeePercent The fee percent to charge upfront, in terms of `JBConstants.MAX_FEE`.
217
+ /// @param holder The address whose tokens are used as collateral and who receives the loan NFT.
222
218
  /// @return loanId The ID of the loan created from borrowing.
223
219
  /// @return The loan created from borrowing.
224
220
  function borrowFrom(
@@ -227,7 +223,8 @@ interface IREVLoans {
227
223
  uint256 minBorrowAmount,
228
224
  uint256 collateralCount,
229
225
  address payable beneficiary,
230
- uint256 prepaidFeePercent
226
+ uint256 prepaidFeePercent,
227
+ address holder
231
228
  )
232
229
  external
233
230
  returns (uint256 loanId, REVLoan memory);
@@ -226,7 +226,8 @@ contract REVnet_Integrations is TestBaseWorkflow {
226
226
  jbDirectory(),
227
227
  FEE_PROJECT_ID,
228
228
  SUCKER_REGISTRY,
229
- makeAddr("loans")
229
+ makeAddr("loans"),
230
+ address(0)
230
231
  );
231
232
 
232
233
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -89,7 +89,8 @@ contract REVAutoIssuanceFuzz_Local is TestBaseWorkflow {
89
89
  jbDirectory(),
90
90
  FEE_PROJECT_ID,
91
91
  SUCKER_REGISTRY,
92
- makeAddr("loans")
92
+ makeAddr("loans"),
93
+ address(0)
93
94
  );
94
95
 
95
96
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -92,7 +92,6 @@ contract REVDeployerRegressions is TestBaseWorkflow {
92
92
 
93
93
  LOANS_CONTRACT = new REVLoans({
94
94
  controller: jbController(),
95
- projects: jbProjects(),
96
95
  revId: FEE_PROJECT_ID,
97
96
  owner: address(this),
98
97
  permit2: permit2(),
@@ -104,7 +103,8 @@ contract REVDeployerRegressions is TestBaseWorkflow {
104
103
  jbDirectory(),
105
104
  FEE_PROJECT_ID,
106
105
  SUCKER_REGISTRY,
107
- address(LOANS_CONTRACT)
106
+ address(LOANS_CONTRACT),
107
+ address(0)
108
108
  );
109
109
 
110
110
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -244,7 +244,6 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
244
244
 
245
245
  LOANS_CONTRACT = new REVLoans({
246
246
  controller: jbController(),
247
- projects: jbProjects(),
248
247
  revId: FEE_PROJECT_ID,
249
248
  owner: address(this),
250
249
  permit2: permit2(),
@@ -256,7 +255,8 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
256
255
  jbDirectory(),
257
256
  FEE_PROJECT_ID,
258
257
  SUCKER_REGISTRY,
259
- address(LOANS_CONTRACT)
258
+ address(LOANS_CONTRACT),
259
+ address(0)
260
260
  );
261
261
 
262
262
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -329,7 +329,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
329
329
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
330
330
 
331
331
  vm.prank(user);
332
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
332
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
333
333
  }
334
334
 
335
335
  // =====================================================================
@@ -788,7 +788,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
788
788
 
789
789
  if (borrowableA > 0) {
790
790
  vm.prank(userA);
791
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokensA, payable(userA), 25);
791
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokensA, payable(userA), 25, userA);
792
792
  }
793
793
 
794
794
  // UserB's tokens should still have proportional cash-out value
@@ -1028,7 +1028,6 @@ contract REVInvincibility_Invariants is StdInvariant, TestBaseWorkflow {
1028
1028
 
1029
1029
  LOANS_CONTRACT = new REVLoans({
1030
1030
  controller: jbController(),
1031
- projects: jbProjects(),
1032
1031
  revId: FEE_PROJECT_ID,
1033
1032
  owner: address(this),
1034
1033
  permit2: permit2(),
@@ -1040,7 +1039,8 @@ contract REVInvincibility_Invariants is StdInvariant, TestBaseWorkflow {
1040
1039
  jbDirectory(),
1041
1040
  FEE_PROJECT_ID,
1042
1041
  SUCKER_REGISTRY,
1043
- address(LOANS_CONTRACT)
1042
+ address(LOANS_CONTRACT),
1043
+ address(0)
1044
1044
  );
1045
1045
 
1046
1046
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -145,7 +145,7 @@ contract REVInvincibilityHandler is JBTest {
145
145
 
146
146
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: TERMINAL});
147
147
  (, REVLoan memory loan) =
148
- LOANS.borrowFrom(REVNET_ID, source, borrowable, receivedTokens, payable(USER), prepaidFee);
148
+ LOANS.borrowFrom(REVNET_ID, source, borrowable, receivedTokens, payable(USER), prepaidFee, USER);
149
149
 
150
150
  COLLATERAL_SUM += receivedTokens;
151
151
  BORROWED_SUM += loan.amount;
@@ -100,7 +100,6 @@ contract REVLifecycle_Local is TestBaseWorkflow {
100
100
 
101
101
  LOANS_CONTRACT = new REVLoans({
102
102
  controller: jbController(),
103
- projects: jbProjects(),
104
103
  revId: FEE_PROJECT_ID,
105
104
  owner: address(this),
106
105
  permit2: permit2(),
@@ -112,7 +111,8 @@ contract REVLifecycle_Local is TestBaseWorkflow {
112
111
  jbDirectory(),
113
112
  FEE_PROJECT_ID,
114
113
  SUCKER_REGISTRY,
115
- address(LOANS_CONTRACT)
114
+ address(LOANS_CONTRACT),
115
+ address(0)
116
116
  );
117
117
 
118
118
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -117,7 +117,7 @@ contract REVLoansCallHandler is JBTest {
117
117
 
118
118
  REVLoanSource memory sauce = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: TERMINAL});
119
119
  (, REVLoan memory lastLoan) =
120
- LOANS.borrowFrom(REVNET_ID, sauce, borrowable, receivedTokens, payable(USER), prepaidFee);
120
+ LOANS.borrowFrom(REVNET_ID, sauce, borrowable, receivedTokens, payable(USER), prepaidFee, USER);
121
121
 
122
122
  COLLATERAL_SUM += receivedTokens;
123
123
  BORROWED_SUM += lastLoan.amount;
@@ -542,7 +542,6 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
542
542
 
543
543
  LOANS_CONTRACT = new REVLoans({
544
544
  controller: jbController(),
545
- projects: jbProjects(),
546
545
  revId: FEE_PROJECT_ID,
547
546
  owner: address(this),
548
547
  permit2: permit2(),
@@ -554,7 +553,8 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
554
553
  jbDirectory(),
555
554
  FEE_PROJECT_ID,
556
555
  SUCKER_REGISTRY,
557
- address(LOANS_CONTRACT)
556
+ address(LOANS_CONTRACT),
557
+ address(0)
558
558
  );
559
559
 
560
560
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -98,7 +98,8 @@ contract ReentrantTerminal is ERC165, IJBPayoutTerminal {
98
98
  0, // minBorrowAmount
99
99
  reenterCollateral,
100
100
  payable(address(this)),
101
- 25 // MIN_PREPAID_FEE_PERCENT
101
+ 25, // MIN_PREPAID_FEE_PERCENT
102
+ address(this)
102
103
  ) {}
103
104
  catch {
104
105
  // Expected to revert if reentrancy guard exists
@@ -383,7 +384,6 @@ contract REVLoansAttacks is TestBaseWorkflow {
383
384
 
384
385
  LOANS_CONTRACT = new REVLoans({
385
386
  controller: jbController(),
386
- projects: jbProjects(),
387
387
  revId: FEE_PROJECT_ID,
388
388
  owner: address(this),
389
389
  permit2: permit2(),
@@ -395,7 +395,8 @@ contract REVLoansAttacks is TestBaseWorkflow {
395
395
  jbDirectory(),
396
396
  FEE_PROJECT_ID,
397
397
  SUCKER_REGISTRY,
398
- address(LOANS_CONTRACT)
398
+ address(LOANS_CONTRACT),
399
+ address(0)
399
400
  );
400
401
 
401
402
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -474,7 +475,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
474
475
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
475
476
 
476
477
  vm.prank(user);
477
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
478
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
478
479
  }
479
480
 
480
481
  // =========================================================================
@@ -646,7 +647,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
646
647
  vm.assume(borrowable > 0);
647
648
 
648
649
  vm.prank(userA);
649
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokensA, payable(userA), 25);
650
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokensA, payable(userA), 25, userA);
650
651
 
651
652
  // After borrowing, tokensA are burned as collateral
652
653
  // But the surplus is adjusted by adding totalBorrowed
@@ -771,7 +772,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
771
772
 
772
773
  // Borrow with max prepaid fee (so no additional fee on immediate repay)
773
774
  vm.prank(USER);
774
- (uint256 loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 500);
775
+ (uint256 loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 500, USER);
775
776
 
776
777
  REVLoan memory loan = LOANS_CONTRACT.loanOf(loanId);
777
778
 
@@ -349,7 +349,6 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
349
349
 
350
350
  LOANS_CONTRACT = new REVLoans({
351
351
  controller: jbController(),
352
- projects: jbProjects(),
353
352
  revId: FEE_PROJECT_ID,
354
353
  owner: address(this),
355
354
  permit2: permit2(),
@@ -361,7 +360,8 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
361
360
  jbDirectory(),
362
361
  FEE_PROJECT_ID,
363
362
  SUCKER_REGISTRY,
364
- address(LOANS_CONTRACT)
363
+ address(LOANS_CONTRACT),
364
+ address(0)
365
365
  );
366
366
 
367
367
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -450,7 +450,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
450
450
  borrowerBalanceBefore = user.balance;
451
451
 
452
452
  vm.prank(user);
453
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
453
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
454
454
 
455
455
  borrowerBalanceAfter = user.balance;
456
456
  }
@@ -492,7 +492,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
492
492
  // Normal borrow.
493
493
  uint256 balBefore = USER.balance;
494
494
  vm.prank(USER);
495
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25);
495
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25, USER);
496
496
  uint256 normalReceived = USER.balance - balBefore;
497
497
 
498
498
  // Revert to snapshot — identical state.
@@ -504,7 +504,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
504
504
 
505
505
  balBefore = USER.balance;
506
506
  vm.prank(USER);
507
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25);
507
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25, USER);
508
508
  uint256 failReceived = USER.balance - balBefore;
509
509
 
510
510
  // The borrower with a failed fee terminal should receive MORE than the normal borrower,
@@ -537,7 +537,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
537
537
  // Normal borrow.
538
538
  uint256 balBefore = USER.balance;
539
539
  vm.prank(USER);
540
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25);
540
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25, USER);
541
541
  uint256 normalReceived = USER.balance - balBefore;
542
542
 
543
543
  // Get the actual borrow amount from the loan to compute expected REV fee.
@@ -555,7 +555,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
555
555
 
556
556
  balBefore = USER.balance;
557
557
  vm.prank(USER);
558
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25);
558
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25, USER);
559
559
  uint256 failReceived = USER.balance - balBefore;
560
560
 
561
561
  // The difference should be the REV fee amount.
@@ -594,7 +594,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
594
594
  assertEq(allowanceBefore, 0, "No pre-existing allowance");
595
595
 
596
596
  vm.prank(USER);
597
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25);
597
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25, USER);
598
598
 
599
599
  // After the borrow, the allowance to the reverting terminal should still be 0
600
600
  // (the catch block decreased it).
@@ -630,7 +630,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
630
630
  // Normal borrow.
631
631
  uint256 tokenBalBefore = TOKEN.balanceOf(USER);
632
632
  vm.prank(USER);
633
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25);
633
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25, USER);
634
634
  uint256 normalReceived = TOKEN.balanceOf(USER) - tokenBalBefore;
635
635
 
636
636
  // Revert to snapshot.
@@ -642,7 +642,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
642
642
 
643
643
  tokenBalBefore = TOKEN.balanceOf(USER);
644
644
  vm.prank(USER);
645
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25);
645
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(USER), 25, USER);
646
646
  uint256 failReceived = TOKEN.balanceOf(USER) - tokenBalBefore;
647
647
 
648
648
  // Failed-fee borrower should receive more tokens.
@@ -699,7 +699,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
699
699
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
700
700
 
701
701
  vm.prank(borrower);
702
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(borrower), 25);
702
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(borrower), 25, borrower);
703
703
  }
704
704
 
705
705
  // After 3 borrows with fee failures, no ETH should be stuck.
@@ -737,7 +737,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
737
737
 
738
738
  uint256 balanceBefore = borrower.balance;
739
739
  vm.prank(borrower);
740
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(borrower), 25);
740
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokens, payable(borrower), 25, borrower);
741
741
  uint256 received = borrower.balance - balanceBefore;
742
742
 
743
743
  // The borrower should always receive something.
@@ -207,7 +207,6 @@ contract REVLoansFindings is TestBaseWorkflow {
207
207
 
208
208
  LOANS_CONTRACT = new REVLoans({
209
209
  controller: jbController(),
210
- projects: jbProjects(),
211
210
  revId: FEE_PROJECT_ID,
212
211
  owner: address(this),
213
212
  permit2: permit2(),
@@ -219,7 +218,8 @@ contract REVLoansFindings is TestBaseWorkflow {
219
218
  jbDirectory(),
220
219
  FEE_PROJECT_ID,
221
220
  SUCKER_REGISTRY,
222
- address(LOANS_CONTRACT)
221
+ address(LOANS_CONTRACT),
222
+ address(0)
223
223
  );
224
224
 
225
225
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -372,7 +372,7 @@ contract REVLoansFindings is TestBaseWorkflow {
372
372
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
373
373
 
374
374
  vm.prank(USER);
375
- (loanId, loan) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, loanable, tokens, payable(USER), 25);
375
+ (loanId, loan) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, loanable, tokens, payable(USER), 25, USER);
376
376
  }
377
377
 
378
378
  //*********************************************************************//
@@ -411,7 +411,7 @@ contract REVLoansFindings is TestBaseWorkflow {
411
411
  );
412
412
 
413
413
  vm.prank(USER);
414
- LOANS_CONTRACT.borrowFrom(REVNET_ID, fakeSource, loanable, tokens, payable(USER), 25);
414
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, fakeSource, loanable, tokens, payable(USER), 25, USER);
415
415
  }
416
416
 
417
417
  //*********************************************************************//
@@ -202,7 +202,6 @@ contract REVLoansRegressions is TestBaseWorkflow {
202
202
 
203
203
  LOANS_CONTRACT = new REVLoans({
204
204
  controller: jbController(),
205
- projects: jbProjects(),
206
205
  revId: FEE_PROJECT_ID,
207
206
  owner: address(this),
208
207
  permit2: permit2(),
@@ -214,7 +213,8 @@ contract REVLoansRegressions is TestBaseWorkflow {
214
213
  jbDirectory(),
215
214
  FEE_PROJECT_ID,
216
215
  SUCKER_REGISTRY,
217
- address(LOANS_CONTRACT)
216
+ address(LOANS_CONTRACT),
217
+ address(0)
218
218
  );
219
219
 
220
220
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -335,7 +335,7 @@ contract REVLoansRegressions is TestBaseWorkflow {
335
335
  );
336
336
 
337
337
  vm.prank(USER);
338
- LOANS_CONTRACT.borrowFrom(REVNET_ID, fakeSource, borrowable, tokens, payable(USER), 500);
338
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, fakeSource, borrowable, tokens, payable(USER), 500, USER);
339
339
  }
340
340
 
341
341
  /// @notice Verify that the configured loan source (real terminal) is properly registered.
@@ -229,7 +229,6 @@ contract REVLoansSourceFeeRecovery is TestBaseWorkflow {
229
229
 
230
230
  LOANS_CONTRACT = new REVLoans({
231
231
  controller: jbController(),
232
- projects: jbProjects(),
233
232
  revId: FEE_PROJECT_ID,
234
233
  owner: address(this),
235
234
  permit2: permit2(),
@@ -241,7 +240,8 @@ contract REVLoansSourceFeeRecovery is TestBaseWorkflow {
241
240
  jbDirectory(),
242
241
  FEE_PROJECT_ID,
243
242
  SUCKER_REGISTRY,
244
- address(LOANS_CONTRACT)
243
+ address(LOANS_CONTRACT),
244
+ address(0)
245
245
  );
246
246
 
247
247
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -310,7 +310,7 @@ contract REVLoansSourceFeeRecovery is TestBaseWorkflow {
310
310
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
311
311
 
312
312
  vm.prank(user);
313
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), 25);
313
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), 25, user);
314
314
  }
315
315
 
316
316
  // =========================================================================
@@ -495,7 +495,7 @@ contract REVLoansSourceFeeRecovery is TestBaseWorkflow {
495
495
 
496
496
  uint256 balBefore = USER.balance;
497
497
  vm.prank(USER);
498
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25);
498
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25, USER);
499
499
 
500
500
  uint256 received = USER.balance - balBefore;
501
501
  assertGt(received, 0, "Borrower should receive ETH even when source fee terminal fails");