@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
@@ -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
  /// @notice Deterministic test for the reallocation sandwich at stage boundaries.
44
47
  /// Documents that a borrower can extract additional value by calling `reallocateCollateralFromLoan` immediately
@@ -145,7 +148,14 @@ contract TestReallocationSandwich is TestBaseWorkflow {
145
148
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
146
149
  HOOK_STORE = new JB721TiersHookStore();
147
150
  EXAMPLE_HOOK = new JB721TiersHook(
148
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
151
+ jbDirectory(),
152
+ jbPermissions(),
153
+ jbPrices(),
154
+ jbRulesets(),
155
+ HOOK_STORE,
156
+ jbSplits(),
157
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
158
+ multisig()
149
159
  );
150
160
  ADDRESS_REGISTRY = new JBAddressRegistry();
151
161
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -153,7 +163,7 @@ contract TestReallocationSandwich is TestBaseWorkflow {
153
163
  MOCK_BUYBACK = new MockBuybackDataHook();
154
164
  LOANS_CONTRACT = new REVLoans({
155
165
  controller: jbController(),
156
- projects: jbProjects(),
166
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
157
167
  revId: FEE_PROJECT_ID,
158
168
  owner: address(this),
159
169
  permit2: permit2(),
@@ -164,7 +174,8 @@ contract TestReallocationSandwich is TestBaseWorkflow {
164
174
  jbDirectory(),
165
175
  FEE_PROJECT_ID,
166
176
  SUCKER_REGISTRY,
167
- address(LOANS_CONTRACT)
177
+ address(LOANS_CONTRACT),
178
+ address(0)
168
179
  );
169
180
 
170
181
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -286,7 +297,8 @@ contract TestReallocationSandwich is TestBaseWorkflow {
286
297
  minBorrowAmount: 0,
287
298
  collateralCount: borrowerTokens,
288
299
  beneficiary: payable(BORROWER),
289
- prepaidFeePercent: prepaidFeePercent
300
+ prepaidFeePercent: prepaidFeePercent,
301
+ holder: BORROWER
290
302
  });
291
303
 
292
304
  uint256 stage1BorrowedAmount = stage1Loan.amount;
@@ -38,23 +38,26 @@ 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 {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 A test harness that exposes REVLoans internal functions for direct testing.
47
50
  /// Used to test _totalBorrowedFrom without needing to set up a full borrow flow.
48
51
  contract REVLoansHarness is REVLoans {
49
52
  constructor(
50
53
  IJBController controller,
51
- IJBProjects projects,
54
+ IJBSuckerRegistry suckerRegistry,
52
55
  uint256 revId,
53
56
  address owner,
54
57
  IPermit2 permit2,
55
58
  address trustedForwarder
56
59
  )
57
- REVLoans(controller, projects, revId, owner, permit2, trustedForwarder)
60
+ REVLoans(controller, suckerRegistry, revId, owner, permit2, trustedForwarder)
58
61
  {}
59
62
 
60
63
  /// @notice Expose _totalBorrowedFrom for testing.
@@ -132,7 +135,14 @@ contract TestRevnetRegressions is TestBaseWorkflow {
132
135
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
133
136
  HOOK_STORE = new JB721TiersHookStore();
134
137
  EXAMPLE_HOOK = new JB721TiersHook(
135
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
138
+ jbDirectory(),
139
+ jbPermissions(),
140
+ jbPrices(),
141
+ jbRulesets(),
142
+ HOOK_STORE,
143
+ jbSplits(),
144
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
145
+ multisig()
136
146
  );
137
147
  ADDRESS_REGISTRY = new JBAddressRegistry();
138
148
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -141,7 +151,7 @@ contract TestRevnetRegressions is TestBaseWorkflow {
141
151
 
142
152
  LOANS_CONTRACT = new REVLoansHarness({
143
153
  controller: jbController(),
144
- projects: jbProjects(),
154
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
145
155
  revId: FEE_PROJECT_ID,
146
156
  owner: address(this),
147
157
  permit2: permit2(),
@@ -153,7 +163,8 @@ contract TestRevnetRegressions is TestBaseWorkflow {
153
163
  jbDirectory(),
154
164
  FEE_PROJECT_ID,
155
165
  SUCKER_REGISTRY,
156
- address(LOANS_CONTRACT)
166
+ address(LOANS_CONTRACT),
167
+ address(0)
157
168
  );
158
169
 
159
170
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -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 {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
@@ -43,6 +45,7 @@ import {JBTokenAmount} from "@bananapus/core-v6/src/structs/JBTokenAmount.sol";
43
45
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
44
46
  import {REVOwner} from "../src/REVOwner.sol";
45
47
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
48
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
46
49
 
47
50
  /// @notice Tests for the split weight adjustment in REVDeployer.beforePayRecordedWith.
48
51
  contract TestSplitWeightAdjustment is TestBaseWorkflow {
@@ -83,7 +86,14 @@ contract TestSplitWeightAdjustment is TestBaseWorkflow {
83
86
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
84
87
  HOOK_STORE = new JB721TiersHookStore();
85
88
  EXAMPLE_HOOK = new JB721TiersHook(
86
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
89
+ jbDirectory(),
90
+ jbPermissions(),
91
+ jbPrices(),
92
+ jbRulesets(),
93
+ HOOK_STORE,
94
+ jbSplits(),
95
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
96
+ multisig()
87
97
  );
88
98
  ADDRESS_REGISTRY = new JBAddressRegistry();
89
99
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -91,7 +101,7 @@ contract TestSplitWeightAdjustment is TestBaseWorkflow {
91
101
  MOCK_BUYBACK = new MockBuybackDataHookMintPath();
92
102
  LOANS_CONTRACT = new REVLoans({
93
103
  controller: jbController(),
94
- projects: jbProjects(),
104
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
95
105
  revId: FEE_PROJECT_ID,
96
106
  owner: address(this),
97
107
  permit2: permit2(),
@@ -102,7 +112,8 @@ contract TestSplitWeightAdjustment is TestBaseWorkflow {
102
112
  jbDirectory(),
103
113
  FEE_PROJECT_ID,
104
114
  SUCKER_REGISTRY,
105
- address(LOANS_CONTRACT)
115
+ address(LOANS_CONTRACT),
116
+ address(0)
106
117
  );
107
118
 
108
119
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -329,7 +340,8 @@ contract TestSplitWeightAdjustment is TestBaseWorkflow {
329
340
  jbDirectory(),
330
341
  FEE_PROJECT_ID,
331
342
  SUCKER_REGISTRY,
332
- address(LOANS_CONTRACT)
343
+ address(LOANS_CONTRACT),
344
+ address(0)
333
345
  );
334
346
  REVDeployer ammDeployer = new REVDeployer{salt: "REVDeployer_AMM"}(
335
347
  jbController(),
@@ -34,6 +34,8 @@ 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 {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
@@ -42,6 +44,8 @@ import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfi
42
44
  import {JB721TierConfigFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierConfigFlags.sol";
43
45
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
44
46
  import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
47
+ import "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
48
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
45
49
  import {REVDeploy721TiersHookConfig} from "../src/structs/REVDeploy721TiersHookConfig.sol";
46
50
  import {REVBaseline721HookConfig} from "../src/structs/REVBaseline721HookConfig.sol";
47
51
  import {REV721TiersHookFlags} from "../src/structs/REV721TiersHookFlags.sol";
@@ -49,6 +53,7 @@ import {REVCroptopAllowedPost} from "../src/structs/REVCroptopAllowedPost.sol";
49
53
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
50
54
  import {REVOwner} from "../src/REVOwner.sol";
51
55
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
56
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
52
57
 
53
58
  /// @notice E2E tests verifying that the split weight adjustment in REVDeployer produces correct token counts
54
59
  /// when payments flow through the full terminal → store → dataHook → mint pipeline.
@@ -102,7 +107,14 @@ contract TestSplitWeightE2E is TestBaseWorkflow {
102
107
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
103
108
  HOOK_STORE = new JB721TiersHookStore();
104
109
  EXAMPLE_HOOK = new JB721TiersHook(
105
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
110
+ jbDirectory(),
111
+ jbPermissions(),
112
+ jbPrices(),
113
+ jbRulesets(),
114
+ HOOK_STORE,
115
+ jbSplits(),
116
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
117
+ multisig()
106
118
  );
107
119
  ADDRESS_REGISTRY = new JBAddressRegistry();
108
120
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -111,7 +123,7 @@ contract TestSplitWeightE2E is TestBaseWorkflow {
111
123
 
112
124
  LOANS_CONTRACT = new REVLoans({
113
125
  controller: jbController(),
114
- projects: jbProjects(),
126
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
115
127
  revId: FEE_PROJECT_ID,
116
128
  owner: address(this),
117
129
  permit2: permit2(),
@@ -123,7 +135,8 @@ contract TestSplitWeightE2E is TestBaseWorkflow {
123
135
  jbDirectory(),
124
136
  FEE_PROJECT_ID,
125
137
  SUCKER_REGISTRY,
126
- address(LOANS_CONTRACT)
138
+ address(LOANS_CONTRACT),
139
+ address(0)
127
140
  );
128
141
 
129
142
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -429,7 +442,8 @@ contract TestSplitWeightE2E is TestBaseWorkflow {
429
442
  jbDirectory(),
430
443
  FEE_PROJECT_ID,
431
444
  SUCKER_REGISTRY,
432
- address(LOANS_CONTRACT)
445
+ address(LOANS_CONTRACT),
446
+ address(0)
433
447
  );
434
448
  REVDeployer ammDeployer = new REVDeployer{salt: "REVDeployer_AMM_E2E"}(
435
449
  jbController(),
@@ -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 {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
@@ -42,6 +44,8 @@ import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfi
42
44
  import {JB721TierConfigFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierConfigFlags.sol";
43
45
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
44
46
  import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
47
+ import "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
48
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
45
49
  import {REVDeploy721TiersHookConfig} from "../src/structs/REVDeploy721TiersHookConfig.sol";
46
50
  import {REVCroptopAllowedPost} from "../src/structs/REVCroptopAllowedPost.sol";
47
51
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
@@ -66,6 +70,7 @@ import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
66
70
  import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
67
71
  import {REVOwner} from "../src/REVOwner.sol";
68
72
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
73
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
69
74
 
70
75
  /// @notice Helper that adds liquidity to and swaps on a V4 pool via the unlock/callback pattern.
71
76
  contract LiquidityHelper is IUnlockCallback {
@@ -294,7 +299,14 @@ contract TestSplitWeightFork is TestBaseWorkflow {
294
299
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
295
300
  HOOK_STORE = new JB721TiersHookStore();
296
301
  EXAMPLE_HOOK = new JB721TiersHook(
297
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
302
+ jbDirectory(),
303
+ jbPermissions(),
304
+ jbPrices(),
305
+ jbRulesets(),
306
+ HOOK_STORE,
307
+ jbSplits(),
308
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
309
+ multisig()
298
310
  );
299
311
  ADDRESS_REGISTRY = new JBAddressRegistry();
300
312
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -323,7 +335,7 @@ contract TestSplitWeightFork is TestBaseWorkflow {
323
335
 
324
336
  LOANS_CONTRACT = new REVLoans({
325
337
  controller: jbController(),
326
- projects: jbProjects(),
338
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
327
339
  revId: FEE_PROJECT_ID,
328
340
  owner: address(this),
329
341
  permit2: permit2(),
@@ -335,7 +347,8 @@ contract TestSplitWeightFork is TestBaseWorkflow {
335
347
  jbDirectory(),
336
348
  FEE_PROJECT_ID,
337
349
  SUCKER_REGISTRY,
338
- address(LOANS_CONTRACT)
350
+ address(LOANS_CONTRACT),
351
+ address(0)
339
352
  );
340
353
 
341
354
  REV_DEPLOYER = new REVDeployer{salt: "REVDeployer_Fork"}(
@@ -31,11 +31,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
31
31
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
32
32
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
33
33
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
34
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
35
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
34
36
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
35
37
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
36
38
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
37
39
  import {REVOwner} from "../src/REVOwner.sol";
38
40
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
41
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
39
42
 
40
43
  /// @notice Documents and verifies that stage transitions change the borrowable amount for the same collateral.
41
44
  /// This is by design: loan value tracks the current bonding curve parameters (cashOutTaxRate),
@@ -138,7 +141,14 @@ contract TestStageTransitionBorrowable is TestBaseWorkflow {
138
141
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
139
142
  HOOK_STORE = new JB721TiersHookStore();
140
143
  EXAMPLE_HOOK = new JB721TiersHook(
141
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
144
+ jbDirectory(),
145
+ jbPermissions(),
146
+ jbPrices(),
147
+ jbRulesets(),
148
+ HOOK_STORE,
149
+ jbSplits(),
150
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
151
+ multisig()
142
152
  );
143
153
  ADDRESS_REGISTRY = new JBAddressRegistry();
144
154
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -146,7 +156,7 @@ contract TestStageTransitionBorrowable is TestBaseWorkflow {
146
156
  MOCK_BUYBACK = new MockBuybackDataHook();
147
157
  LOANS_CONTRACT = new REVLoans({
148
158
  controller: jbController(),
149
- projects: jbProjects(),
159
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
150
160
  revId: FEE_PROJECT_ID,
151
161
  owner: address(this),
152
162
  permit2: permit2(),
@@ -157,7 +167,8 @@ contract TestStageTransitionBorrowable is TestBaseWorkflow {
157
167
  jbDirectory(),
158
168
  FEE_PROJECT_ID,
159
169
  SUCKER_REGISTRY,
160
- address(LOANS_CONTRACT)
170
+ address(LOANS_CONTRACT),
171
+ address(0)
161
172
  );
162
173
 
163
174
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -33,11 +33,14 @@ import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
33
33
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
34
34
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
35
35
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
36
+ import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
37
+ import {IJB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721CheckpointsDeployer.sol";
36
38
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
37
39
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
38
40
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
39
41
  import {REVOwner} from "../src/REVOwner.sol";
40
42
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
43
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
41
44
 
42
45
  /// @notice Tests for default operator permissions including SET_ROUTER_TERMINAL.
43
46
  /// Verifies that all default split operator permissions are granted correctly.
@@ -79,7 +82,14 @@ contract TestSwapTerminalPermission is TestBaseWorkflow {
79
82
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
80
83
  HOOK_STORE = new JB721TiersHookStore();
81
84
  EXAMPLE_HOOK = new JB721TiersHook(
82
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
85
+ jbDirectory(),
86
+ jbPermissions(),
87
+ jbPrices(),
88
+ jbRulesets(),
89
+ HOOK_STORE,
90
+ jbSplits(),
91
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
92
+ multisig()
83
93
  );
84
94
  ADDRESS_REGISTRY = new JBAddressRegistry();
85
95
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -87,7 +97,7 @@ contract TestSwapTerminalPermission is TestBaseWorkflow {
87
97
  MOCK_BUYBACK = new MockBuybackDataHook();
88
98
  LOANS_CONTRACT = new REVLoans({
89
99
  controller: jbController(),
90
- projects: jbProjects(),
100
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
91
101
  revId: FEE_PROJECT_ID,
92
102
  owner: address(this),
93
103
  permit2: permit2(),
@@ -98,7 +108,8 @@ contract TestSwapTerminalPermission is TestBaseWorkflow {
98
108
  jbDirectory(),
99
109
  FEE_PROJECT_ID,
100
110
  SUCKER_REGISTRY,
101
- address(LOANS_CONTRACT)
111
+ address(LOANS_CONTRACT),
112
+ address(0)
102
113
  );
103
114
 
104
115
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -38,10 +38,13 @@ 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 {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
  /// @title TestUint112Overflow
47
50
  /// @notice Tests for uint112 truncation fix in REVLoans._adjust()
@@ -91,7 +94,14 @@ contract TestUint112Overflow is TestBaseWorkflow {
91
94
  SUCKER_REGISTRY = new JBSuckerRegistry(jbDirectory(), jbPermissions(), multisig(), address(0));
92
95
  HOOK_STORE = new JB721TiersHookStore();
93
96
  EXAMPLE_HOOK = new JB721TiersHook(
94
- jbDirectory(), jbPermissions(), jbPrices(), jbRulesets(), HOOK_STORE, jbSplits(), multisig()
97
+ jbDirectory(),
98
+ jbPermissions(),
99
+ jbPrices(),
100
+ jbRulesets(),
101
+ HOOK_STORE,
102
+ jbSplits(),
103
+ IJB721CheckpointsDeployer(address(new JB721CheckpointsDeployer())),
104
+ multisig()
95
105
  );
96
106
  ADDRESS_REGISTRY = new JBAddressRegistry();
97
107
  HOOK_DEPLOYER = new JB721TiersHookDeployer(EXAMPLE_HOOK, HOOK_STORE, ADDRESS_REGISTRY, multisig());
@@ -106,7 +116,7 @@ contract TestUint112Overflow is TestBaseWorkflow {
106
116
 
107
117
  LOANS_CONTRACT = new REVLoans({
108
118
  controller: jbController(),
109
- projects: jbProjects(),
119
+ suckerRegistry: IJBSuckerRegistry(address(new MockSuckerRegistry())),
110
120
  revId: FEE_PROJECT_ID,
111
121
  owner: address(this),
112
122
  permit2: permit2(),
@@ -118,7 +128,8 @@ contract TestUint112Overflow is TestBaseWorkflow {
118
128
  jbDirectory(),
119
129
  FEE_PROJECT_ID,
120
130
  SUCKER_REGISTRY,
121
- address(LOANS_CONTRACT)
131
+ address(LOANS_CONTRACT),
132
+ address(0)
122
133
  );
123
134
 
124
135
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
@@ -265,7 +276,7 @@ contract TestUint112Overflow is TestBaseWorkflow {
265
276
 
266
277
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
267
278
  vm.prank(user);
268
- (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee);
279
+ (loanId,) = LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, tokenCount, payable(user), prepaidFee, user);
269
280
  }
270
281
 
271
282
  /// @notice Verify loan creation with a reasonable borrow amount succeeds.
@@ -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 {REVOwner} from "../src/REVOwner.sol";
43
45
  import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
44
46
  import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
47
+ import {MockSuckerRegistry} from "./mock/MockSuckerRegistry.sol";
45
48
 
46
49
  /// @notice Tests for PR #105: zero-amount loan guard and mint-before-adjust ordering.
47
50
  contract TestZeroAmountLoanGuard is TestBaseWorkflow {
@@ -87,7 +90,14 @@ contract TestZeroAmountLoanGuard 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 TestZeroAmountLoanGuard 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 TestZeroAmountLoanGuard 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 TestZeroAmountLoanGuard 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
  // -----------------------------------------------------------------------
@@ -38,10 +38,13 @@ 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 {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 #16: zero repayment prevention.
47
50
  contract TestZeroRepayment is TestBaseWorkflow {
@@ -87,7 +90,14 @@ contract TestZeroRepayment 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 TestZeroRepayment 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 TestZeroRepayment 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 TestZeroRepayment 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 Repaying with zero borrow amount and zero collateral return should revert.