@rev-net/core-v6 0.0.18 → 0.0.19

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 (64) hide show
  1. package/ADMINISTRATION.md +14 -4
  2. package/ARCHITECTURE.md +13 -10
  3. package/AUDIT_INSTRUCTIONS.md +39 -18
  4. package/CHANGE_LOG.md +79 -1
  5. package/README.md +10 -5
  6. package/RISKS.md +12 -11
  7. package/SKILLS.md +27 -12
  8. package/USER_JOURNEYS.md +15 -14
  9. package/foundry.toml +1 -1
  10. package/package.json +1 -1
  11. package/script/Deploy.s.sol +42 -4
  12. package/src/REVDeployer.sol +20 -305
  13. package/src/REVLoans.sol +24 -29
  14. package/src/REVOwner.sol +430 -0
  15. package/src/interfaces/IREVDeployer.sol +4 -10
  16. package/src/interfaces/IREVOwner.sol +10 -0
  17. package/test/REV.integrations.t.sol +14 -1
  18. package/test/REVAutoIssuanceFuzz.t.sol +14 -1
  19. package/test/REVDeployerRegressions.t.sol +17 -2
  20. package/test/REVInvincibility.t.sol +31 -3
  21. package/test/REVLifecycle.t.sol +16 -1
  22. package/test/REVLoans.invariants.t.sol +16 -1
  23. package/test/REVLoansAttacks.t.sol +16 -1
  24. package/test/REVLoansFeeRecovery.t.sol +16 -1
  25. package/test/REVLoansFindings.t.sol +16 -1
  26. package/test/REVLoansRegressions.t.sol +16 -1
  27. package/test/REVLoansSourceFeeRecovery.t.sol +16 -1
  28. package/test/REVLoansSourced.t.sol +16 -1
  29. package/test/REVLoansUnSourced.t.sol +16 -1
  30. package/test/TestBurnHeldTokens.t.sol +16 -1
  31. package/test/TestCEIPattern.t.sol +16 -1
  32. package/test/TestCashOutCallerValidation.t.sol +19 -4
  33. package/test/TestConversionDocumentation.t.sol +16 -1
  34. package/test/TestCrossCurrencyReclaim.t.sol +16 -1
  35. package/test/TestCrossSourceReallocation.t.sol +16 -1
  36. package/test/TestERC2771MetaTx.t.sol +16 -1
  37. package/test/TestEmptyBuybackSpecs.t.sol +18 -3
  38. package/test/TestFlashLoanSurplus.t.sol +16 -1
  39. package/test/TestHookArrayOOB.t.sol +17 -2
  40. package/test/TestLiquidationBehavior.t.sol +16 -1
  41. package/test/TestLoanSourceRotation.t.sol +16 -1
  42. package/test/TestLoansCashOutDelay.t.sol +21 -6
  43. package/test/TestLongTailEconomics.t.sol +16 -1
  44. package/test/TestLowFindings.t.sol +16 -1
  45. package/test/TestMixedFixes.t.sol +16 -1
  46. package/test/TestPermit2Signatures.t.sol +16 -1
  47. package/test/TestReallocationSandwich.t.sol +16 -1
  48. package/test/TestRevnetRegressions.t.sol +16 -1
  49. package/test/TestSplitWeightAdjustment.t.sol +43 -19
  50. package/test/TestSplitWeightE2E.t.sol +26 -2
  51. package/test/TestSplitWeightFork.t.sol +16 -1
  52. package/test/TestStageTransitionBorrowable.t.sol +16 -1
  53. package/test/TestSwapTerminalPermission.t.sol +16 -1
  54. package/test/TestUint112Overflow.t.sol +16 -1
  55. package/test/TestZeroRepayment.t.sol +16 -1
  56. package/test/audit/LoanIdOverflowGuard.t.sol +16 -1
  57. package/test/fork/ForkTestBase.sol +16 -1
  58. package/test/fork/TestPermit2PaymentFork.t.sol +4 -3
  59. package/test/regression/TestBurnPermissionRequired.t.sol +16 -1
  60. package/test/regression/TestCashOutBuybackFeeLeak.t.sol +15 -1
  61. package/test/regression/TestCrossRevnetLiquidation.t.sol +16 -1
  62. package/test/regression/TestCumulativeLoanCounter.t.sol +16 -1
  63. package/test/regression/TestLiquidateGapHandling.t.sol +16 -1
  64. package/test/regression/TestZeroPriceFeed.t.sol +16 -1
@@ -40,6 +40,8 @@ import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
40
40
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
41
41
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
42
42
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
43
+ import {REVOwner} from "../src/REVOwner.sol";
44
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
43
45
 
44
46
  /// @notice Tests for PR #16: zero repayment prevention.
45
47
  contract TestZeroRepayment is TestBaseWorkflow {
@@ -49,6 +51,8 @@ contract TestZeroRepayment is TestBaseWorkflow {
49
51
  // forge-lint: disable-next-line(mixed-case-variable)
50
52
  REVDeployer REV_DEPLOYER;
51
53
  // forge-lint: disable-next-line(mixed-case-variable)
54
+ REVOwner REV_OWNER;
55
+ // forge-lint: disable-next-line(mixed-case-variable)
52
56
  JB721TiersHook EXAMPLE_HOOK;
53
57
  // forge-lint: disable-next-line(mixed-case-variable)
54
58
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -102,6 +106,14 @@ contract TestZeroRepayment is TestBaseWorkflow {
102
106
  permit2: permit2(),
103
107
  trustedForwarder: TRUSTED_FORWARDER
104
108
  });
109
+ REV_OWNER = new REVOwner(
110
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
111
+ jbDirectory(),
112
+ FEE_PROJECT_ID,
113
+ SUCKER_REGISTRY,
114
+ address(LOANS_CONTRACT)
115
+ );
116
+
105
117
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
106
118
  jbController(),
107
119
  SUCKER_REGISTRY,
@@ -110,8 +122,11 @@ contract TestZeroRepayment is TestBaseWorkflow {
110
122
  PUBLISHER,
111
123
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
112
124
  address(LOANS_CONTRACT),
113
- TRUSTED_FORWARDER
125
+ TRUSTED_FORWARDER,
126
+ address(REV_OWNER)
114
127
  );
128
+
129
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
115
130
  vm.prank(multisig());
116
131
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
117
132
  _deployFeeProject();
@@ -42,6 +42,8 @@ import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressReg
42
42
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
43
43
  // Helper that provides empty 721 tier configs for revnet deployment.
44
44
  import {REVEmpty721Config} from "../helpers/REVEmpty721Config.sol";
45
+ import {REVOwner} from "../../src/REVOwner.sol";
46
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
45
47
 
46
48
  /// @notice Regression tests for the loan ID overflow guard in REVLoans.
47
49
  /// @dev The totalLoansBorrowedFor counter must never exceed _ONE_TRILLION (1e12).
@@ -74,6 +76,8 @@ contract LoanIdOverflowGuard is TestBaseWorkflow {
74
76
  // forge-lint: disable-next-line(mixed-case-variable)
75
77
  REVDeployer REV_DEPLOYER;
76
78
  // forge-lint: disable-next-line(mixed-case-variable)
79
+ REVOwner REV_OWNER;
80
+ // forge-lint: disable-next-line(mixed-case-variable)
77
81
  JB721TiersHook EXAMPLE_HOOK;
78
82
  // forge-lint: disable-next-line(mixed-case-variable)
79
83
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -159,6 +163,14 @@ contract LoanIdOverflowGuard is TestBaseWorkflow {
159
163
  });
160
164
 
161
165
  // Deploy the REVDeployer with a deterministic salt.
166
+ REV_OWNER = new REVOwner(
167
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
168
+ jbDirectory(),
169
+ FEE_PROJECT_ID,
170
+ SUCKER_REGISTRY,
171
+ address(LOANS_CONTRACT)
172
+ );
173
+
162
174
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
163
175
  jbController(),
164
176
  SUCKER_REGISTRY,
@@ -167,9 +179,12 @@ contract LoanIdOverflowGuard is TestBaseWorkflow {
167
179
  PUBLISHER,
168
180
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
169
181
  address(LOANS_CONTRACT),
170
- TRUSTED_FORWARDER
182
+ TRUSTED_FORWARDER,
183
+ address(REV_OWNER)
171
184
  );
172
185
 
186
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
187
+
173
188
  // Approve the deployer to configure the fee project.
174
189
  vm.prank(multisig());
175
190
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
@@ -71,6 +71,8 @@ import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
71
71
  import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
72
72
 
73
73
  import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
74
+ import {REVOwner} from "../../src/REVOwner.sol";
75
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
74
76
 
75
77
  /// @notice Helper that adds liquidity to a V4 pool via the unlock/callback pattern.
76
78
  contract LiquidityHelper is IUnlockCallback {
@@ -237,6 +239,8 @@ abstract contract ForkTestBase is TestBaseWorkflow {
237
239
  // forge-lint: disable-next-line(mixed-case-variable)
238
240
  REVDeployer REV_DEPLOYER;
239
241
  // forge-lint: disable-next-line(mixed-case-variable)
242
+ REVOwner REV_OWNER;
243
+ // forge-lint: disable-next-line(mixed-case-variable)
240
244
  JBBuybackHook BUYBACK_HOOK;
241
245
  // forge-lint: disable-next-line(mixed-case-variable)
242
246
  JBBuybackHookRegistry BUYBACK_REGISTRY;
@@ -330,6 +334,14 @@ abstract contract ForkTestBase is TestBaseWorkflow {
330
334
  trustedForwarder: TRUSTED_FORWARDER
331
335
  });
332
336
 
337
+ REV_OWNER = new REVOwner(
338
+ IJBBuybackHookRegistry(address(BUYBACK_REGISTRY)),
339
+ jbDirectory(),
340
+ FEE_PROJECT_ID,
341
+ SUCKER_REGISTRY,
342
+ address(LOANS_CONTRACT)
343
+ );
344
+
333
345
  REV_DEPLOYER = new REVDeployer{salt: "REVDeployer_Fork"}(
334
346
  jbController(),
335
347
  SUCKER_REGISTRY,
@@ -338,9 +350,12 @@ abstract contract ForkTestBase is TestBaseWorkflow {
338
350
  PUBLISHER,
339
351
  IJBBuybackHookRegistry(address(BUYBACK_REGISTRY)),
340
352
  address(LOANS_CONTRACT),
341
- TRUSTED_FORWARDER
353
+ TRUSTED_FORWARDER,
354
+ address(REV_OWNER)
342
355
  );
343
356
 
357
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
358
+
344
359
  vm.prank(multisig());
345
360
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
346
361
 
@@ -149,14 +149,15 @@ contract TestPermit2PaymentFork is ForkTestBase {
149
149
  sigDeadline: sigDeadline, amount: amount, expiration: expiration, nonce: nonce, signature: sig
150
150
  });
151
151
 
152
- // Encode as metadata with the "permit2" key targeting the terminal, plus a zero "quote"
153
- // so the buyback hook skips the TWAP pool lookup (no pool exists for testToken).
152
+ // Encode as metadata with the "permit2" key targeting the terminal, plus a "quote" entry
153
+ // targeting the buyback hook with minimumSwapAmountOut=1 so the buyback hook skips the
154
+ // TWAP oracle and falls through to normal minting (no V4 pool has liquidity for testToken).
154
155
  bytes4[] memory ids = new bytes4[](2);
155
156
  bytes[] memory datas = new bytes[](2);
156
157
  ids[0] = JBMetadataResolver.getId("permit2", address(jbMultiTerminal()));
157
158
  datas[0] = abi.encode(allowance);
158
159
  ids[1] = JBMetadataResolver.getId("quote", address(BUYBACK_HOOK));
159
- datas[1] = abi.encode(uint256(0), uint256(0));
160
+ datas[1] = abi.encode(uint256(0), uint256(1));
160
161
  metadata = JBMetadataResolver.createMetadata(ids, datas);
161
162
  }
162
163
 
@@ -40,6 +40,8 @@ import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/
40
40
  import {REVEmpty721Config} from "../helpers/REVEmpty721Config.sol";
41
41
  import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
42
42
  import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
43
+ import {REVOwner} from "../../src/REVOwner.sol";
44
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
43
45
 
44
46
  /// @notice Validates that borrowFrom() reverts with a clear error when the caller hasn't granted BURN_TOKENS
45
47
  /// permission to the REVLoans contract.
@@ -52,6 +54,8 @@ contract TestBurnPermissionRequired is TestBaseWorkflow {
52
54
  // forge-lint: disable-next-line(mixed-case-variable)
53
55
  REVDeployer REV_DEPLOYER;
54
56
  // forge-lint: disable-next-line(mixed-case-variable)
57
+ REVOwner REV_OWNER;
58
+ // forge-lint: disable-next-line(mixed-case-variable)
55
59
  JB721TiersHook EXAMPLE_HOOK;
56
60
  // forge-lint: disable-next-line(mixed-case-variable)
57
61
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -104,6 +108,14 @@ contract TestBurnPermissionRequired is TestBaseWorkflow {
104
108
  permit2: permit2(),
105
109
  trustedForwarder: TRUSTED_FORWARDER
106
110
  });
111
+ REV_OWNER = new REVOwner(
112
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
113
+ jbDirectory(),
114
+ FEE_PROJECT_ID,
115
+ SUCKER_REGISTRY,
116
+ address(LOANS_CONTRACT)
117
+ );
118
+
107
119
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
108
120
  jbController(),
109
121
  SUCKER_REGISTRY,
@@ -112,8 +124,11 @@ contract TestBurnPermissionRequired is TestBaseWorkflow {
112
124
  PUBLISHER,
113
125
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
114
126
  address(LOANS_CONTRACT),
115
- TRUSTED_FORWARDER
127
+ TRUSTED_FORWARDER,
128
+ address(REV_OWNER)
116
129
  );
130
+
131
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
117
132
  vm.prank(multisig());
118
133
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
119
134
  _deployFeeProject();
@@ -35,6 +35,8 @@ import {REVSuckerDeploymentConfig} from "../../src/structs/REVSuckerDeploymentCo
35
35
  import {REVLoans} from "../../src/REVLoans.sol";
36
36
  import {REVEmpty721Config} from "../helpers/REVEmpty721Config.sol";
37
37
  import {MockBuybackCashOutRecorder} from "../mock/MockBuybackCashOutRecorder.sol";
38
+ import {REVOwner} from "../../src/REVOwner.sol";
39
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
38
40
 
39
41
  /// @title TestCashOutBuybackFeeLeak
40
42
  /// @notice Proves the buyback hook callback receives only the non-fee cashOutCount (not the full count).
@@ -46,6 +48,7 @@ contract TestCashOutBuybackFeeLeak is TestBaseWorkflow {
46
48
  address private constant TRUSTED_FORWARDER = 0xB2b5841DBeF766d4b521221732F9B618fCf34A87;
47
49
 
48
50
  REVDeployer internal revDeployer;
51
+ REVOwner internal revOwner;
49
52
  MockBuybackCashOutRecorder internal mockBuyback;
50
53
  JB721TiersHook internal exampleHook;
51
54
  IJB721TiersHookDeployer internal hookDeployer;
@@ -81,6 +84,14 @@ contract TestCashOutBuybackFeeLeak is TestBaseWorkflow {
81
84
  trustedForwarder: TRUSTED_FORWARDER
82
85
  });
83
86
 
87
+ revOwner = new REVOwner(
88
+ IJBBuybackHookRegistry(address(mockBuyback)),
89
+ jbDirectory(),
90
+ feeProjectId,
91
+ IJBSuckerRegistry(address(suckerRegistry)),
92
+ address(loans)
93
+ );
94
+
84
95
  revDeployer = new REVDeployer{salt: REV_DEPLOYER_SALT}(
85
96
  jbController(),
86
97
  suckerRegistry,
@@ -89,9 +100,12 @@ contract TestCashOutBuybackFeeLeak is TestBaseWorkflow {
89
100
  publisher,
90
101
  IJBBuybackHookRegistry(address(mockBuyback)),
91
102
  address(loans),
92
- TRUSTED_FORWARDER
103
+ TRUSTED_FORWARDER,
104
+ address(revOwner)
93
105
  );
94
106
 
107
+ revOwner.initialize(IREVDeployer(address(revDeployer)));
108
+
95
109
  vm.prank(multisig());
96
110
  jbProjects().approve(address(revDeployer), feeProjectId);
97
111
 
@@ -37,6 +37,8 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
37
37
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
38
38
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
39
39
  import {REVEmpty721Config} from "../helpers/REVEmpty721Config.sol";
40
+ import {REVOwner} from "../../src/REVOwner.sol";
41
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
40
42
 
41
43
  /// @notice Validates that liquidateExpiredLoansFrom rejects loan number ranges that would overflow into another
42
44
  /// revnet's namespace.
@@ -49,6 +51,8 @@ contract TestCrossRevnetLiquidation is TestBaseWorkflow {
49
51
  // forge-lint: disable-next-line(mixed-case-variable)
50
52
  REVDeployer REV_DEPLOYER;
51
53
  // forge-lint: disable-next-line(mixed-case-variable)
54
+ REVOwner REV_OWNER;
55
+ // forge-lint: disable-next-line(mixed-case-variable)
52
56
  JB721TiersHook EXAMPLE_HOOK;
53
57
  // forge-lint: disable-next-line(mixed-case-variable)
54
58
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -102,6 +106,14 @@ contract TestCrossRevnetLiquidation is TestBaseWorkflow {
102
106
  permit2: permit2(),
103
107
  trustedForwarder: TRUSTED_FORWARDER
104
108
  });
109
+ REV_OWNER = new REVOwner(
110
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
111
+ jbDirectory(),
112
+ FEE_PROJECT_ID,
113
+ SUCKER_REGISTRY,
114
+ address(LOANS_CONTRACT)
115
+ );
116
+
105
117
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
106
118
  jbController(),
107
119
  SUCKER_REGISTRY,
@@ -110,8 +122,11 @@ contract TestCrossRevnetLiquidation is TestBaseWorkflow {
110
122
  PUBLISHER,
111
123
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
112
124
  address(LOANS_CONTRACT),
113
- TRUSTED_FORWARDER
125
+ TRUSTED_FORWARDER,
126
+ address(REV_OWNER)
114
127
  );
128
+
129
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
115
130
  vm.prank(multisig());
116
131
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
117
132
  _deployFeeProject();
@@ -38,6 +38,8 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
38
38
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
39
39
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
40
40
  import {REVEmpty721Config} from "../helpers/REVEmpty721Config.sol";
41
+ import {REVOwner} from "../../src/REVOwner.sol";
42
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
41
43
 
42
44
  /// @notice totalLoansBorrowedFor is a cumulative counter, not an active loan count.
43
45
  /// @dev The rename from numberOfLoansFor to totalLoansBorrowedFor clarifies that the counter only increments
@@ -50,6 +52,8 @@ contract TestCumulativeLoanCounter is TestBaseWorkflow {
50
52
  // forge-lint: disable-next-line(mixed-case-variable)
51
53
  REVDeployer REV_DEPLOYER;
52
54
  // forge-lint: disable-next-line(mixed-case-variable)
55
+ REVOwner REV_OWNER;
56
+ // forge-lint: disable-next-line(mixed-case-variable)
53
57
  JB721TiersHook EXAMPLE_HOOK;
54
58
  // forge-lint: disable-next-line(mixed-case-variable)
55
59
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -106,6 +110,14 @@ contract TestCumulativeLoanCounter is TestBaseWorkflow {
106
110
  permit2: permit2(),
107
111
  trustedForwarder: TRUSTED_FORWARDER
108
112
  });
113
+ REV_OWNER = new REVOwner(
114
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
115
+ jbDirectory(),
116
+ FEE_PROJECT_ID,
117
+ SUCKER_REGISTRY,
118
+ address(LOANS_CONTRACT)
119
+ );
120
+
109
121
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
110
122
  jbController(),
111
123
  SUCKER_REGISTRY,
@@ -114,8 +126,11 @@ contract TestCumulativeLoanCounter is TestBaseWorkflow {
114
126
  PUBLISHER,
115
127
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
116
128
  address(LOANS_CONTRACT),
117
- TRUSTED_FORWARDER
129
+ TRUSTED_FORWARDER,
130
+ address(REV_OWNER)
118
131
  );
132
+
133
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
119
134
  vm.prank(multisig());
120
135
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
121
136
  _deployFeeProject();
@@ -39,6 +39,8 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
39
39
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
40
40
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
41
41
  import {REVEmpty721Config} from "../helpers/REVEmpty721Config.sol";
42
+ import {REVOwner} from "../../src/REVOwner.sol";
43
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
42
44
 
43
45
  /// @notice liquidateExpiredLoansFrom halts on deleted loan gaps.
44
46
  /// @dev Before the fix, the function used `break` when encountering a deleted loan (createdAt == 0),
@@ -51,6 +53,8 @@ contract TestLiquidateGapHandling is TestBaseWorkflow {
51
53
  // forge-lint: disable-next-line(mixed-case-variable)
52
54
  REVDeployer REV_DEPLOYER;
53
55
  // forge-lint: disable-next-line(mixed-case-variable)
56
+ REVOwner REV_OWNER;
57
+ // forge-lint: disable-next-line(mixed-case-variable)
54
58
  JB721TiersHook EXAMPLE_HOOK;
55
59
  // forge-lint: disable-next-line(mixed-case-variable)
56
60
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -108,6 +112,14 @@ contract TestLiquidateGapHandling is TestBaseWorkflow {
108
112
  permit2: permit2(),
109
113
  trustedForwarder: TRUSTED_FORWARDER
110
114
  });
115
+ REV_OWNER = new REVOwner(
116
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
117
+ jbDirectory(),
118
+ FEE_PROJECT_ID,
119
+ SUCKER_REGISTRY,
120
+ address(LOANS_CONTRACT)
121
+ );
122
+
111
123
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
112
124
  jbController(),
113
125
  SUCKER_REGISTRY,
@@ -116,8 +128,11 @@ contract TestLiquidateGapHandling is TestBaseWorkflow {
116
128
  PUBLISHER,
117
129
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
118
130
  address(LOANS_CONTRACT),
119
- TRUSTED_FORWARDER
131
+ TRUSTED_FORWARDER,
132
+ address(REV_OWNER)
120
133
  );
134
+
135
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
121
136
  vm.prank(multisig());
122
137
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
123
138
  _deployFeeProject();
@@ -40,6 +40,8 @@ import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressReg
40
40
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
41
41
  import {REVEmpty721Config} from "../helpers/REVEmpty721Config.sol";
42
42
  import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
43
+ import {REVOwner} from "../../src/REVOwner.sol";
44
+ import {IREVDeployer} from "../../src/interfaces/IREVDeployer.sol";
43
45
 
44
46
  /// @notice Verifies that `_totalBorrowedFrom` gracefully handles zero-price feeds.
45
47
  /// @dev When a cross-currency price feed returns 0 (e.g., inverse truncation at low decimals), the affected source
@@ -53,6 +55,8 @@ contract TestZeroPriceFeed is TestBaseWorkflow {
53
55
  // forge-lint: disable-next-line(mixed-case-variable)
54
56
  REVDeployer REV_DEPLOYER;
55
57
  // forge-lint: disable-next-line(mixed-case-variable)
58
+ REVOwner REV_OWNER;
59
+ // forge-lint: disable-next-line(mixed-case-variable)
56
60
  JB721TiersHook EXAMPLE_HOOK;
57
61
  // forge-lint: disable-next-line(mixed-case-variable)
58
62
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -117,6 +121,14 @@ contract TestZeroPriceFeed is TestBaseWorkflow {
117
121
  trustedForwarder: TRUSTED_FORWARDER
118
122
  });
119
123
 
124
+ REV_OWNER = new REVOwner(
125
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
126
+ jbDirectory(),
127
+ FEE_PROJECT_ID,
128
+ SUCKER_REGISTRY,
129
+ address(LOANS_CONTRACT)
130
+ );
131
+
120
132
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
121
133
  jbController(),
122
134
  SUCKER_REGISTRY,
@@ -125,9 +137,12 @@ contract TestZeroPriceFeed is TestBaseWorkflow {
125
137
  PUBLISHER,
126
138
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
127
139
  address(LOANS_CONTRACT),
128
- TRUSTED_FORWARDER
140
+ TRUSTED_FORWARDER,
141
+ address(REV_OWNER)
129
142
  );
130
143
 
144
+ REV_OWNER.initialize(IREVDeployer(address(REV_DEPLOYER)));
145
+
131
146
  vm.prank(multisig());
132
147
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
133
148