@rev-net/core-v6 0.0.29 → 0.0.31

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 (77) 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 +28 -3
  9. package/package.json +8 -8
  10. package/references/operations.md +1 -1
  11. package/script/Deploy.s.sol +26 -4
  12. package/src/REVDeployer.sol +4 -2
  13. package/src/REVHiddenTokens.sol +149 -0
  14. package/src/REVLoans.sol +192 -199
  15. package/src/REVOwner.sol +51 -14
  16. package/src/interfaces/IREVHiddenTokens.sol +53 -0
  17. package/src/interfaces/IREVLoans.sol +8 -6
  18. package/test/REV.integrations.t.sol +12 -2
  19. package/test/REVAutoIssuanceFuzz.t.sol +12 -2
  20. package/test/REVDeployerRegressions.t.sol +14 -3
  21. package/test/REVInvincibility.t.sol +27 -8
  22. package/test/REVInvincibilityHandler.sol +1 -1
  23. package/test/REVLifecycle.t.sol +14 -3
  24. package/test/REVLoans.invariants.t.sol +15 -4
  25. package/test/REVLoansAttacks.t.sol +19 -7
  26. package/test/REVLoansFeeRecovery.t.sol +24 -13
  27. package/test/REVLoansFindings.t.sol +16 -5
  28. package/test/REVLoansRegressions.t.sol +15 -4
  29. package/test/REVLoansSourceFeeRecovery.t.sol +16 -5
  30. package/test/REVLoansSourced.t.sol +60 -25
  31. package/test/REVLoansUnSourced.t.sol +15 -4
  32. package/test/TestBurnHeldTokens.t.sol +14 -3
  33. package/test/TestCEIPattern.t.sol +19 -7
  34. package/test/TestCashOutCallerValidation.t.sol +15 -4
  35. package/test/TestConversionDocumentation.t.sol +14 -3
  36. package/test/TestCrossCurrencyReclaim.t.sol +14 -3
  37. package/test/TestCrossSourceReallocation.t.sol +15 -4
  38. package/test/TestERC2771MetaTx.t.sol +18 -5
  39. package/test/TestEmptyBuybackSpecs.t.sol +14 -3
  40. package/test/TestFlashLoanSurplus.t.sol +15 -4
  41. package/test/TestHiddenTokens.t.sol +431 -0
  42. package/test/TestHookArrayOOB.t.sol +14 -3
  43. package/test/TestLiquidationBehavior.t.sol +16 -5
  44. package/test/TestLoanSourceRotation.t.sol +20 -7
  45. package/test/TestLoansCashOutDelay.t.sol +18 -7
  46. package/test/TestLongTailEconomics.t.sol +14 -3
  47. package/test/TestLowFindings.t.sol +25 -9
  48. package/test/TestMixedFixes.t.sol +19 -8
  49. package/test/TestPermit2Signatures.t.sol +15 -4
  50. package/test/TestReallocationSandwich.t.sol +16 -4
  51. package/test/TestRevnetRegressions.t.sol +16 -5
  52. package/test/TestSplitWeightAdjustment.t.sol +16 -4
  53. package/test/TestSplitWeightE2E.t.sol +18 -4
  54. package/test/TestSplitWeightFork.t.sol +16 -3
  55. package/test/TestStageTransitionBorrowable.t.sol +14 -3
  56. package/test/TestSwapTerminalPermission.t.sol +14 -3
  57. package/test/TestUint112Overflow.t.sol +15 -4
  58. package/test/TestZeroAmountLoanGuard.t.sol +15 -4
  59. package/test/TestZeroRepayment.t.sol +15 -4
  60. package/test/audit/CodexPhantomSurplusTerminal.t.sol +367 -0
  61. package/test/audit/LoanIdOverflowGuard.t.sol +16 -5
  62. package/test/audit/NemesisOperatorDelegation.t.sol +289 -0
  63. package/test/fork/ForkTestBase.sol +18 -4
  64. package/test/fork/TestLoanBorrowFork.t.sol +2 -1
  65. package/test/fork/TestLoanERC20Fork.t.sol +4 -2
  66. package/test/fork/TestLoanTransferFork.t.sol +12 -2
  67. package/test/helpers/MaliciousContracts.sol +1 -1
  68. package/test/mock/MockBuybackCashOutRecorder.sol +2 -0
  69. package/test/mock/MockBuybackDataHook.sol +3 -1
  70. package/test/mock/MockBuybackDataHookMintPath.sol +2 -0
  71. package/test/mock/MockSuckerRegistry.sol +17 -0
  72. package/test/regression/TestBurnPermissionRequired.t.sol +16 -5
  73. package/test/regression/TestCashOutBuybackFeeLeak.t.sol +16 -3
  74. package/test/regression/TestCrossRevnetLiquidation.t.sol +14 -3
  75. package/test/regression/TestCumulativeLoanCounter.t.sol +15 -4
  76. package/test/regression/TestLiquidateGapHandling.t.sol +15 -4
  77. package/test/regression/TestZeroPriceFeed.t.sol +17 -6
@@ -32,6 +32,8 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
32
32
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
33
33
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
34
34
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
35
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
36
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
35
37
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
36
38
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
37
39
  import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforePayRecordedContext.sol";
@@ -40,6 +42,7 @@ import {JBTokenAmount} from "@bananapus/core-v6/src/structs/JBTokenAmount.sol";
40
42
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
41
43
  import {REVOwner} from "../src/REVOwner.sol";
42
44
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
45
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
43
46
 
44
47
  /// @notice Tests for PR #22: fix/c2-hook-array-oob
45
48
  /// Verifies that the fix for the hook array out-of-bounds bug works correctly.
@@ -84,7 +87,14 @@ contract TestHookArrayOOB is TestBaseWorkflow {
84
87
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
85
88
  HOOK_STORE = new JB721TiersHookStore();
86
89
  EXAMPLE_HOOK = new JB721TiersHook(
87
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
90
+ jbDirectory(),
91
+ jbPermissions(),
92
+ jbPrices(),
93
+ jbRulesets(),
94
+ HOOK_STORE,
95
+ jbSplits(),
96
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
97
+ multisig()
88
98
  );
89
99
  ADDRESS_REGISTRY = new JBAddressRegistry();
90
100
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -92,7 +102,7 @@ contract TestHookArrayOOB is TestBaseWorkflow {
92
102
  MOCK_BUYBACK = new MockBuybackDataHook();
93
103
  LOANS_CONTRACT = new REVLoans({
94
104
  controller: jbController(),
95
- projects: jbProjects(),
105
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
96
106
  revId: FEE_PROJECT_ID,
97
107
  owner: address(this),
98
108
  permit2: permit2(),
@@ -103,7 +113,8 @@ contract TestHookArrayOOB is TestBaseWorkflow {
103
113
  jbDirectory(),
104
114
  FEE_PROJECT_ID,
105
115
  SUCKER_REGISTRY,
106
- address(LOANS_CONTRACT)
116
+ address(LOANS_CONTRACT),
117
+ address(0)
107
118
  );
108
119
 
109
120
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -37,11 +37,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
37
37
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
38
38
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
39
39
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
40
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
41
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
40
42
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
41
43
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
42
44
  import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
43
45
  import {REVOwner} from "../src/REVOwner.sol";
44
46
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
47
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
45
48
 
46
49
  /// @notice Tests for PR #10: liquidation behavior documentation and collateral burn mechanics.
47
50
  contract TestLiquidationBehavior is TestBaseWorkflow {
@@ -87,7 +90,14 @@ contract TestLiquidationBehavior is TestBaseWorkflow {
87
90
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
88
91
  HOOK_STORE = new JB721TiersHookStore();
89
92
  EXAMPLE_HOOK = new JB721TiersHook(
90
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
93
+ jbDirectory(),
94
+ jbPermissions(),
95
+ jbPrices(),
96
+ jbRulesets(),
97
+ HOOK_STORE,
98
+ jbSplits(),
99
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
100
+ multisig()
91
101
  );
92
102
  ADDRESS_REGISTRY = new JBAddressRegistry();
93
103
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -100,7 +110,7 @@ contract TestLiquidationBehavior is TestBaseWorkflow {
100
110
  .addPriceFeedFor(0, uint32(uint160(address(TOKEN))), uint32(uint160(JBConstants.NATIVE_TOKEN)), priceFeed);
101
111
  LOANS_CONTRACT = new REVLoans({
102
112
  controller: jbController(),
103
- projects: jbProjects(),
113
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
104
114
  revId: FEE_PROJECT_ID,
105
115
  owner: address(this),
106
116
  permit2: permit2(),
@@ -111,7 +121,8 @@ contract TestLiquidationBehavior is TestBaseWorkflow {
111
121
  jbDirectory(),
112
122
  FEE_PROJECT_ID,
113
123
  SUCKER_REGISTRY,
114
- address(LOANS_CONTRACT)
124
+ address(LOANS_CONTRACT),
125
+ address(0)
115
126
  );
116
127
 
117
128
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -247,7 +258,7 @@ contract TestLiquidationBehavior is TestBaseWorkflow {
247
258
  );
248
259
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
249
260
  vm.prank(user);
250
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
261
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
251
262
  }
252
263
 
253
264
  /// @notice Verify that collateral is burned (not escrowed) — totalCollateralOf increases and loans contract holds
@@ -273,7 +284,7 @@ contract TestLiquidationBehavior is TestBaseWorkflow {
273
284
  );
274
285
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
275
286
  vm.prank(USER);
276
- LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25);
287
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(USER), 25, USER);
277
288
 
278
289
  uint256 totalCollateralAfterBorrow = LOANS_CONTRACT.totalCollateralOf(REVNET_ID);
279
290
 
@@ -36,12 +36,15 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
36
36
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
37
37
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
38
38
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
39
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
40
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
39
41
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
40
42
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
41
43
  import {JBSingleAllowance} from "@bananapus/core-v6/src/structs/JBSingleAllowance.sol";
42
44
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
43
45
  import {REVOwner} from "../src/REVOwner.sol";
44
46
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
47
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
45
48
 
46
49
  /// @notice Tests for loan source rotation: verify behavior when loans are taken from different sources (tokens)
47
50
  /// and that existing loans remain valid and repayable after new sources are introduced.
@@ -90,7 +93,14 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
90
93
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
91
94
  HOOK_STORE = new JB721TiersHookStore();
92
95
  EXAMPLE_HOOK = new JB721TiersHook(
93
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
96
+ jbDirectory(),
97
+ jbPermissions(),
98
+ jbPrices(),
99
+ jbRulesets(),
100
+ HOOK_STORE,
101
+ jbSplits(),
102
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
103
+ multisig()
94
104
  );
95
105
  ADDRESS_REGISTRY = new JBAddressRegistry();
96
106
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -108,7 +118,7 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
108
118
 
109
119
  LOANS_CONTRACT = new REVLoans({
110
120
  controller: jbController(),
111
- projects: jbProjects(),
121
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
112
122
  revId: FEE_PROJECT_ID,
113
123
  owner: address(this),
114
124
  permit2: permit2(),
@@ -120,7 +130,8 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
120
130
  jbDirectory(),
121
131
  FEE_PROJECT_ID,
122
132
  SUCKER_REGISTRY,
123
- address(LOANS_CONTRACT)
133
+ address(LOANS_CONTRACT),
134
+ address(0)
124
135
  );
125
136
 
126
137
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -271,7 +282,7 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
271
282
  );
272
283
 
273
284
  vm.prank(user);
274
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), 25);
285
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), 25, user);
275
286
  }
276
287
 
277
288
  //*********************************************************************//
@@ -323,7 +334,8 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
323
334
  );
324
335
 
325
336
  vm.prank(user2);
326
- (uint256 loanId2,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, tokenSource, 0, user2Tokens, payable(user2), 25);
337
+ (uint256 loanId2,) =
338
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, tokenSource, 0, user2Tokens, payable(user2), 25, user2);
327
339
  assertGt(loanId2, 0, "TOKEN loan should be created");
328
340
 
329
341
  // Both sources should now be registered.
@@ -415,7 +427,8 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
415
427
  );
416
428
 
417
429
  vm.prank(user2);
418
- (uint256 loanId2,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, ethSource2, 0, user2Tokens, payable(user2), 25);
430
+ (uint256 loanId2,) =
431
+ LOANS_CONTRACT.borrowFrom(REVNET_ID, ethSource2, 0, user2Tokens, payable(user2), 25, user2);
419
432
  assertGt(loanId2, 0, "second loan should be created");
420
433
 
421
434
  // First loan should be unaffected.
@@ -530,7 +543,7 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
530
543
  );
531
544
 
532
545
  vm.prank(user2);
533
- (uint256 loanId2,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, ethSource, 0, tokens, payable(user2), 25);
546
+ (uint256 loanId2,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, ethSource, 0, tokens, payable(user2), 25, user2);
534
547
  assertGt(loanId2, 0, "second loan should succeed");
535
548
 
536
549
  uint256 countAfterSecond = LOANS_CONTRACT.totalLoansBorrowedFor(REVNET_ID);
@@ -34,11 +34,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
34
34
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
35
35
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
36
36
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
37
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
38
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
37
39
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
38
40
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
39
41
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
40
42
  import {REVOwner} from "../src/REVOwner.sol";
41
43
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
44
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
42
45
 
43
46
  struct FeeProjectConfig {
44
47
  REVConfig configuration;
@@ -202,7 +205,14 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
202
205
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
203
206
  HOOK_STORE = new JB721TiersHookStore();
204
207
  EXAMPLE_HOOK = new JB721TiersHook(
205
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
208
+ jbDirectory(),
209
+ jbPermissions(),
210
+ jbPrices(),
211
+ jbRulesets(),
212
+ HOOK_STORE,
213
+ jbSplits(),
214
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
215
+ multisig()
206
216
  );
207
217
  ADDRESS_REGISTRY = new JBAddressRegistry();
208
218
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -211,7 +221,7 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
211
221
 
212
222
  LOANS_CONTRACT = new REVLoans({
213
223
  controller: jbController(),
214
- projects: jbProjects(),
224
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
215
225
  revId: FEE_PROJECT_ID,
216
226
  owner: address(this),
217
227
  permit2: permit2(),
@@ -223,7 +233,8 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
223
233
  jbDirectory(),
224
234
  FEE_PROJECT_ID,
225
235
  SUCKER_REGISTRY,
226
- address(LOANS_CONTRACT)
236
+ address(LOANS_CONTRACT),
237
+ address(0)
227
238
  );
228
239
 
229
240
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -347,7 +358,7 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
347
358
  abi.encodeWithSelector(REVLoans.REVLoans_CashOutDelayNotFinished.selector, cashOutDelay, block.timestamp)
348
359
  );
349
360
  vm.prank(USER);
350
- LOANS_CONTRACT.borrowFrom(DELAYED_REVNET_ID, source, 1, tokenCount, payable(USER), 25);
361
+ LOANS_CONTRACT.borrowFrom(DELAYED_REVNET_ID, source, 1, tokenCount, payable(USER), 25, USER);
351
362
  }
352
363
 
353
364
  /// @notice After warping past the delay, borrowableAmountFrom should return a non-zero value.
@@ -393,7 +404,7 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
393
404
  // Borrow — should succeed.
394
405
  vm.prank(USER);
395
406
  (uint256 loanId,) =
396
- LOANS_CONTRACT.borrowFrom(DELAYED_REVNET_ID, source, borrowable, tokenCount, payable(USER), 25);
407
+ LOANS_CONTRACT.borrowFrom(DELAYED_REVNET_ID, source, borrowable, tokenCount, payable(USER), 25, USER);
397
408
  assertGt(loanId, 0, "Should have created a loan");
398
409
  }
399
410
 
@@ -431,7 +442,7 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
431
442
  // Borrow — should succeed without any delay.
432
443
  vm.prank(USER);
433
444
  (uint256 loanId,) =
434
- LOANS_CONTRACT.borrowFrom(NORMAL_REVNET_ID, source, borrowable, tokenCount, payable(USER), 25);
445
+ LOANS_CONTRACT.borrowFrom(NORMAL_REVNET_ID, source, borrowable, tokenCount, payable(USER), 25, USER);
435
446
  assertGt(loanId, 0, "Should have created a loan");
436
447
  }
437
448
 
@@ -477,6 +488,6 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
477
488
  abi.encodeWithSelector(REVLoans.REVLoans_CashOutDelayNotFinished.selector, cashOutDelay, block.timestamp)
478
489
  );
479
490
  vm.prank(USER);
480
- LOANS_CONTRACT.borrowFrom(DELAYED_REVNET_ID, source, 1, tokenCount, payable(USER), 25);
491
+ LOANS_CONTRACT.borrowFrom(DELAYED_REVNET_ID, source, 1, tokenCount, payable(USER), 25, USER);
481
492
  }
482
493
  }
@@ -32,11 +32,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
32
32
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
33
33
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
34
34
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
35
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
36
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
35
37
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
36
38
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
37
39
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
38
40
  import {REVOwner} from "../src/REVOwner.sol";
39
41
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
42
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
40
43
 
41
44
  /// @notice Long-tail economic simulation: run a revnet through multiple stage transitions with many payments
42
45
  /// and cash outs, verifying value conservation and bonding curve consistency.
@@ -92,7 +95,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
92
95
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
93
96
  HOOK_STORE = new JB721TiersHookStore();
94
97
  EXAMPLE_HOOK = new JB721TiersHook(
95
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
98
+ jbDirectory(),
99
+ jbPermissions(),
100
+ jbPrices(),
101
+ jbRulesets(),
102
+ HOOK_STORE,
103
+ jbSplits(),
104
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
105
+ multisig()
96
106
  );
97
107
  ADDRESS_REGISTRY = new JBAddressRegistry();
98
108
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -101,7 +111,7 @@ contract TestLongTailEconomics is TestBaseWorkflow {
101
111
 
102
112
  LOANS_CONTRACT = new REVLoans({
103
113
  controller: jbController(),
104
- projects: jbProjects(),
114
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
105
115
  revId: FEE_PROJECT_ID,
106
116
  owner: address(this),
107
117
  permit2: permit2(),
@@ -113,7 +123,8 @@ contract TestLongTailEconomics is TestBaseWorkflow {
113
123
  jbDirectory(),
114
124
  FEE_PROJECT_ID,
115
125
  SUCKER_REGISTRY,
116
- address(LOANS_CONTRACT)
126
+ address(LOANS_CONTRACT),
127
+ address(0)
117
128
  );
118
129
 
119
130
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -37,11 +37,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
37
37
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
38
38
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
39
39
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
40
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
41
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
40
42
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
41
43
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
42
44
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
43
45
  import {REVOwner} from "../src/REVOwner.sol";
44
46
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
47
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
45
48
 
46
49
  struct FeeProjectConfig {
47
50
  REVConfig configuration;
@@ -275,7 +278,14 @@ contract TestLowFindings is TestBaseWorkflow {
275
278
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
276
279
  HOOK_STORE = new JB721TiersHookStore();
277
280
  EXAMPLE_HOOK = new JB721TiersHook(
278
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
281
+ jbDirectory(),
282
+ jbPermissions(),
283
+ jbPrices(),
284
+ jbRulesets(),
285
+ HOOK_STORE,
286
+ jbSplits(),
287
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
288
+ multisig()
279
289
  );
280
290
  ADDRESS_REGISTRY = new JBAddressRegistry();
281
291
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -290,7 +300,7 @@ contract TestLowFindings is TestBaseWorkflow {
290
300
 
291
301
  LOANS_CONTRACT = new REVLoans({
292
302
  controller: jbController(),
293
- projects: jbProjects(),
303
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
294
304
  revId: FEE_PROJECT_ID,
295
305
  owner: address(this),
296
306
  permit2: permit2(),
@@ -302,7 +312,8 @@ contract TestLowFindings is TestBaseWorkflow {
302
312
  jbDirectory(),
303
313
  FEE_PROJECT_ID,
304
314
  SUCKER_REGISTRY,
305
- address(LOANS_CONTRACT)
315
+ address(LOANS_CONTRACT),
316
+ address(0)
306
317
  );
307
318
 
308
319
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -388,7 +399,8 @@ contract TestLowFindings is TestBaseWorkflow {
388
399
  uint256 minPrepaid = LOANS_CONTRACT.MIN_PREPAID_FEE_PERCENT();
389
400
 
390
401
  vm.prank(USER);
391
- (uint256 loanId,) = LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid);
402
+ (uint256 loanId,) =
403
+ LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid, USER);
392
404
 
393
405
  REVLoan memory loanBefore = LOANS_CONTRACT.loanOf(loanId);
394
406
  assertGt(loanBefore.amount, 0, "Loan should have an amount");
@@ -435,7 +447,8 @@ contract TestLowFindings is TestBaseWorkflow {
435
447
  uint256 minPrepaid = LOANS_CONTRACT.MIN_PREPAID_FEE_PERCENT();
436
448
 
437
449
  vm.prank(USER);
438
- (uint256 loanId,) = LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid);
450
+ (uint256 loanId,) =
451
+ LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid, USER);
439
452
 
440
453
  REVLoan memory loanBefore = LOANS_CONTRACT.loanOf(loanId);
441
454
  assertGt(loanBefore.amount, 0, "Loan should exist before liquidation");
@@ -479,7 +492,8 @@ contract TestLowFindings is TestBaseWorkflow {
479
492
  uint256 minPrepaid = LOANS_CONTRACT.MIN_PREPAID_FEE_PERCENT();
480
493
 
481
494
  vm.prank(USER);
482
- (uint256 loanId,) = LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid);
495
+ (uint256 loanId,) =
496
+ LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid, USER);
483
497
 
484
498
  REVLoan memory loanBefore = LOANS_CONTRACT.loanOf(loanId);
485
499
  assertGt(loanBefore.collateral, 1, "Need >1 collateral for partial return");
@@ -536,7 +550,8 @@ contract TestLowFindings is TestBaseWorkflow {
536
550
  uint256 minPrepaid = LOANS_CONTRACT.MIN_PREPAID_FEE_PERCENT();
537
551
 
538
552
  vm.prank(USER);
539
- (uint256 loanId,) = LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid);
553
+ (uint256 loanId,) =
554
+ LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid, USER);
540
555
 
541
556
  REVLoan memory loan = LOANS_CONTRACT.loanOf(loanId);
542
557
 
@@ -587,7 +602,8 @@ contract TestLowFindings is TestBaseWorkflow {
587
602
 
588
603
  // Borrow the full max against all tokens.
589
604
  vm.prank(USER);
590
- (uint256 loanId,) = LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid);
605
+ (uint256 loanId,) =
606
+ LOANS_CONTRACT.borrowFrom(revnetId, source, loanable, tokens, payable(USER), minPrepaid, USER);
591
607
 
592
608
  REVLoan memory loanBefore = LOANS_CONTRACT.loanOf(loanId);
593
609
  assertGt(loanBefore.collateral, 0, "Loan should have collateral");
@@ -656,6 +672,6 @@ contract TestLowFindings is TestBaseWorkflow {
656
672
  // Attempt to borrow with 1 wei of collateral -- bonding curve returns 0, should revert.
657
673
  vm.prank(USER);
658
674
  vm.expectRevert(REVLoans.REVLoans_ZeroBorrowAmount.selector);
659
- LOANS_CONTRACT.borrowFrom(revnetId, source, 0, 1, payable(USER), minPrepaid);
675
+ LOANS_CONTRACT.borrowFrom(revnetId, source, 0, 1, payable(USER), minPrepaid, USER);
660
676
  }
661
677
  }
@@ -35,11 +35,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
35
35
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
36
36
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
37
37
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
38
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
39
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
38
40
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
39
41
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
40
42
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
41
43
  import {REVOwner} from "../src/REVOwner.sol";
42
44
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
45
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
43
46
 
44
47
  /// @notice Tests for PR #32: liquidation boundary, reallocate msg.value, and decimal normalization fixes.
45
48
  contract TestMixedFixes is TestBaseWorkflow {
@@ -85,7 +88,14 @@ contract TestMixedFixes is TestBaseWorkflow {
85
88
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
86
89
  HOOK_STORE = new JB721TiersHookStore();
87
90
  EXAMPLE_HOOK = new JB721TiersHook(
88
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
91
+ jbDirectory(),
92
+ jbPermissions(),
93
+ jbPrices(),
94
+ jbRulesets(),
95
+ HOOK_STORE,
96
+ jbSplits(),
97
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
98
+ multisig()
89
99
  );
90
100
  ADDRESS_REGISTRY = new JBAddressRegistry();
91
101
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -98,7 +108,7 @@ contract TestMixedFixes is TestBaseWorkflow {
98
108
  .addPriceFeedFor(0, uint32(uint160(address(TOKEN))), uint32(uint160(JBConstants.NATIVE_TOKEN)), priceFeed);
99
109
  LOANS_CONTRACT = new REVLoans({
100
110
  controller: jbController(),
101
- projects: jbProjects(),
111
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
102
112
  revId: FEE_PROJECT_ID,
103
113
  owner: address(this),
104
114
  permit2: permit2(),
@@ -109,7 +119,8 @@ contract TestMixedFixes is TestBaseWorkflow {
109
119
  jbDirectory(),
110
120
  FEE_PROJECT_ID,
111
121
  SUCKER_REGISTRY,
112
- address(LOANS_CONTRACT)
122
+ address(LOANS_CONTRACT),
123
+ address(0)
113
124
  );
114
125
 
115
126
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -245,7 +256,7 @@ contract TestMixedFixes is TestBaseWorkflow {
245
256
  );
246
257
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
247
258
  vm.prank(user);
248
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
259
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
249
260
  }
250
261
 
251
262
  /// @notice At exactly LOAN_LIQUIDATION_DURATION, determineSourceFeeAmount should revert with LoanExpired (>=
@@ -431,7 +442,7 @@ contract TestMixedFixes is TestBaseWorkflow {
431
442
  REVLoanSource memory ethSource = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
432
443
  vm.prank(USER);
433
444
  (uint256 loanId, REVLoan memory loan) =
434
- LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, ethSource, 0, tokenCount, payable(USER), 25);
445
+ LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, ethSource, 0, tokenCount, payable(USER), 25, USER);
435
446
 
436
447
  // Verify loan created and TOKEN source has zero borrowed.
437
448
  assertTrue(loanId != 0, "ETH loan should be created");
@@ -481,7 +492,7 @@ contract TestMixedFixes is TestBaseWorkflow {
481
492
  REVLoanSource memory tokenSource = REVLoanSource({token: address(TOKEN), terminal: jbMultiTerminal()});
482
493
  vm.prank(USER);
483
494
  (uint256 loanId, REVLoan memory loan) =
484
- LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, tokenSource, 0, smallCollateral, payable(USER), 25);
495
+ LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, tokenSource, 0, smallCollateral, payable(USER), 25, USER);
485
496
 
486
497
  assertTrue(loanId != 0, "TOKEN loan should be created");
487
498
  assertTrue(loan.amount > 0, "Loan amount should be nonzero");
@@ -537,7 +548,7 @@ contract TestMixedFixes is TestBaseWorkflow {
537
548
  REVLoanSource memory tokenSource = REVLoanSource({token: address(TOKEN), terminal: jbMultiTerminal()});
538
549
  vm.prank(USER);
539
550
  (uint256 tokenLoanId,) =
540
- LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, tokenSource, 0, smallCollateral, payable(USER), 25);
551
+ LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, tokenSource, 0, smallCollateral, payable(USER), 25, USER);
541
552
  assertTrue(tokenLoanId != 0, "TOKEN loan should be created");
542
553
 
543
554
  // STEP 3: Pay ETH to create ETH surplus.
@@ -558,7 +569,7 @@ contract TestMixedFixes is TestBaseWorkflow {
558
569
  REVLoanSource memory ethSource = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
559
570
  vm.prank(USER);
560
571
  (uint256 ethLoanId,) =
561
- LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, ethSource, 0, ethCollateral, payable(USER), 25);
572
+ LOANS_CONTRACT.borrowFrom(MIXED_REVNET_ID, ethSource, 0, ethCollateral, payable(USER), 25, USER);
562
573
  assertTrue(ethLoanId != 0, "ETH loan should be created");
563
574
 
564
575
  // Both sources should have tracked borrows.
@@ -38,6 +38,8 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
38
38
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
39
39
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
40
40
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
41
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
42
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
41
43
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
42
44
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
43
45
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
@@ -47,6 +49,7 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
47
49
  import {JBFees} from "@bananapus/core-v6/src/libraries/JBFees.sol";
48
50
  import {REVOwner} from "../src/REVOwner.sol";
49
51
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
52
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
50
53
 
51
54
  struct Permit2ProjectConfig {
52
55
  REVConfig configuration;
@@ -243,7 +246,14 @@ contract TestPermit2Signatures is TestBaseWorkflow {
243
246
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
244
247
  HOOK_STORE = new JB721TiersHookStore();
245
248
  EXAMPLE_HOOK = new JB721TiersHook(
246
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
249
+ jbDirectory(),
250
+ jbPermissions(),
251
+ jbPrices(),
252
+ jbRulesets(),
253
+ HOOK_STORE,
254
+ jbSplits(),
255
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
256
+ multisig()
247
257
  );
248
258
  ADDRESS_REGISTRY = new JBAddressRegistry();
249
259
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -258,7 +268,7 @@ contract TestPermit2Signatures is TestBaseWorkflow {
258
268
 
259
269
  LOANS_CONTRACT = new REVLoans({
260
270
  controller: jbController(),
261
- projects: jbProjects(),
271
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
262
272
  revId: FEE_PROJECT_ID,
263
273
  owner: address(this),
264
274
  permit2: permit2(),
@@ -270,7 +280,8 @@ contract TestPermit2Signatures is TestBaseWorkflow {
270
280
  jbDirectory(),
271
281
  FEE_PROJECT_ID,
272
282
  SUCKER_REGISTRY,
273
- address(LOANS_CONTRACT)
283
+ address(LOANS_CONTRACT),
284
+ address(0)
274
285
  );
275
286
 
276
287
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -398,7 +409,7 @@ contract TestPermit2Signatures is TestBaseWorkflow {
398
409
  REVLoanSource memory source = REVLoanSource({token: address(TOKEN), terminal: jbMultiTerminal()});
399
410
 
400
411
  vm.prank(user);
401
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
412
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
402
413
  }
403
414
 
404
415
  // =========================================================================