@rev-net/core-v6 0.0.18 → 0.0.20

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 +78 -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 +37 -4
  12. package/src/REVDeployer.sol +23 -305
  13. package/src/REVLoans.sol +24 -29
  14. package/src/REVOwner.sol +429 -0
  15. package/src/interfaces/IREVDeployer.sol +4 -10
  16. package/src/interfaces/IREVOwner.sol +10 -0
  17. package/test/REV.integrations.t.sol +12 -1
  18. package/test/REVAutoIssuanceFuzz.t.sol +12 -1
  19. package/test/REVDeployerRegressions.t.sol +15 -2
  20. package/test/REVInvincibility.t.sol +27 -3
  21. package/test/REVLifecycle.t.sol +14 -1
  22. package/test/REVLoans.invariants.t.sol +14 -1
  23. package/test/REVLoansAttacks.t.sol +14 -1
  24. package/test/REVLoansFeeRecovery.t.sol +14 -1
  25. package/test/REVLoansFindings.t.sol +14 -1
  26. package/test/REVLoansRegressions.t.sol +14 -1
  27. package/test/REVLoansSourceFeeRecovery.t.sol +14 -1
  28. package/test/REVLoansSourced.t.sol +14 -1
  29. package/test/REVLoansUnSourced.t.sol +14 -1
  30. package/test/TestBurnHeldTokens.t.sol +14 -1
  31. package/test/TestCEIPattern.t.sol +15 -1
  32. package/test/TestCashOutCallerValidation.t.sol +17 -4
  33. package/test/TestConversionDocumentation.t.sol +14 -1
  34. package/test/TestCrossCurrencyReclaim.t.sol +14 -1
  35. package/test/TestCrossSourceReallocation.t.sol +15 -1
  36. package/test/TestERC2771MetaTx.t.sol +14 -1
  37. package/test/TestEmptyBuybackSpecs.t.sol +17 -3
  38. package/test/TestFlashLoanSurplus.t.sol +15 -1
  39. package/test/TestHookArrayOOB.t.sol +16 -2
  40. package/test/TestLiquidationBehavior.t.sol +15 -1
  41. package/test/TestLoanSourceRotation.t.sol +14 -1
  42. package/test/TestLoansCashOutDelay.t.sol +19 -6
  43. package/test/TestLongTailEconomics.t.sol +14 -1
  44. package/test/TestLowFindings.t.sol +14 -1
  45. package/test/TestMixedFixes.t.sol +15 -1
  46. package/test/TestPermit2Signatures.t.sol +14 -1
  47. package/test/TestReallocationSandwich.t.sol +15 -1
  48. package/test/TestRevnetRegressions.t.sol +14 -1
  49. package/test/TestSplitWeightAdjustment.t.sol +41 -19
  50. package/test/TestSplitWeightE2E.t.sol +23 -2
  51. package/test/TestSplitWeightFork.t.sol +14 -1
  52. package/test/TestStageTransitionBorrowable.t.sol +15 -1
  53. package/test/TestSwapTerminalPermission.t.sol +15 -1
  54. package/test/TestUint112Overflow.t.sol +14 -1
  55. package/test/TestZeroRepayment.t.sol +15 -1
  56. package/test/audit/LoanIdOverflowGuard.t.sol +14 -1
  57. package/test/fork/ForkTestBase.sol +14 -1
  58. package/test/fork/TestPermit2PaymentFork.t.sol +4 -3
  59. package/test/regression/TestBurnPermissionRequired.t.sol +15 -1
  60. package/test/regression/TestCashOutBuybackFeeLeak.t.sol +13 -1
  61. package/test/regression/TestCrossRevnetLiquidation.t.sol +15 -1
  62. package/test/regression/TestCumulativeLoanCounter.t.sol +15 -1
  63. package/test/regression/TestLiquidateGapHandling.t.sol +15 -1
  64. package/test/regression/TestZeroPriceFeed.t.sol +14 -1
@@ -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 Cross-currency reclaim tests: verify cash-out behavior when a revnet's baseCurrency differs from the
42
44
  /// terminal token currency, and when price feeds return various values.
@@ -47,6 +49,8 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
47
49
  // forge-lint: disable-next-line(mixed-case-variable)
48
50
  REVDeployer REV_DEPLOYER;
49
51
  // forge-lint: disable-next-line(mixed-case-variable)
52
+ REVOwner REV_OWNER;
53
+ // forge-lint: disable-next-line(mixed-case-variable)
50
54
  JB721TiersHook EXAMPLE_HOOK;
51
55
  // forge-lint: disable-next-line(mixed-case-variable)
52
56
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -104,6 +108,14 @@ contract TestCrossCurrencyReclaim is TestBaseWorkflow {
104
108
  trustedForwarder: TRUSTED_FORWARDER
105
109
  });
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,7 +124,8 @@ contract TestCrossCurrencyReclaim 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
  );
117
130
 
118
131
  vm.prank(multisig());
@@ -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 Tests for PR #13: cross-source reallocation prevention.
44
46
  contract TestCrossSourceReallocation is TestBaseWorkflow {
@@ -48,6 +50,8 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
48
50
  // forge-lint: disable-next-line(mixed-case-variable)
49
51
  REVDeployer REV_DEPLOYER;
50
52
  // forge-lint: disable-next-line(mixed-case-variable)
53
+ REVOwner REV_OWNER;
54
+ // forge-lint: disable-next-line(mixed-case-variable)
51
55
  JB721TiersHook EXAMPLE_HOOK;
52
56
  // forge-lint: disable-next-line(mixed-case-variable)
53
57
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -101,6 +105,14 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
101
105
  permit2: permit2(),
102
106
  trustedForwarder: TRUSTED_FORWARDER
103
107
  });
108
+ REV_OWNER = new REVOwner(
109
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
110
+ jbDirectory(),
111
+ FEE_PROJECT_ID,
112
+ SUCKER_REGISTRY,
113
+ address(LOANS_CONTRACT)
114
+ );
115
+
104
116
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
105
117
  jbController(),
106
118
  SUCKER_REGISTRY,
@@ -109,8 +121,10 @@ contract TestCrossSourceReallocation is TestBaseWorkflow {
109
121
  PUBLISHER,
110
122
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
111
123
  address(LOANS_CONTRACT),
112
- TRUSTED_FORWARDER
124
+ TRUSTED_FORWARDER,
125
+ address(REV_OWNER)
113
126
  );
127
+
114
128
  vm.prank(multisig());
115
129
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
116
130
  _deployFeeProject();
@@ -43,6 +43,8 @@ import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/
43
43
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
44
44
  import {ERC2771Forwarder} from "@openzeppelin/contracts/metatx/ERC2771Forwarder.sol";
45
45
  import {ERC2771ForwarderMock, ForwardRequest} from "@bananapus/core-v6/test/mock/ERC2771ForwarderMock.sol";
46
+ import {REVOwner} from "../src/REVOwner.sol";
47
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
46
48
 
47
49
  struct MetaTxProjectConfig {
48
50
  REVConfig configuration;
@@ -63,6 +65,8 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
63
65
  // forge-lint: disable-next-line(mixed-case-variable)
64
66
  REVDeployer REV_DEPLOYER;
65
67
  // forge-lint: disable-next-line(mixed-case-variable)
68
+ REVOwner REV_OWNER;
69
+ // forge-lint: disable-next-line(mixed-case-variable)
66
70
  JB721TiersHook EXAMPLE_HOOK;
67
71
  // forge-lint: disable-next-line(mixed-case-variable)
68
72
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -294,6 +298,14 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
294
298
  trustedForwarder: FORWARDER_ADDRESS
295
299
  });
296
300
 
301
+ REV_OWNER = new REVOwner(
302
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
303
+ jbDirectory(),
304
+ FEE_PROJECT_ID,
305
+ SUCKER_REGISTRY,
306
+ address(LOANS_CONTRACT)
307
+ );
308
+
297
309
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
298
310
  jbController(),
299
311
  SUCKER_REGISTRY,
@@ -302,7 +314,8 @@ contract TestERC2771MetaTx is TestBaseWorkflow {
302
314
  PUBLISHER,
303
315
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
304
316
  address(LOANS_CONTRACT),
305
- FORWARDER_ADDRESS
317
+ FORWARDER_ADDRESS,
318
+ address(REV_OWNER)
306
319
  );
307
320
 
308
321
  // Approve the deployer to configure the project.
@@ -37,6 +37,8 @@ import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBefor
37
37
  import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
38
38
  import {JBTokenAmount} from "@bananapus/core-v6/src/structs/JBTokenAmount.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 Regression tests for the empty buyback hook specifications fix.
42
44
  /// When JBBuybackHook determines minting is cheaper than swapping, it returns an empty
@@ -49,6 +51,8 @@ contract TestEmptyBuybackSpecs 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;
@@ -92,6 +96,14 @@ contract TestEmptyBuybackSpecs is TestBaseWorkflow {
92
96
  permit2: permit2(),
93
97
  trustedForwarder: TRUSTED_FORWARDER
94
98
  });
99
+ REV_OWNER = new REVOwner(
100
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK_MINT_PATH)),
101
+ jbDirectory(),
102
+ FEE_PROJECT_ID,
103
+ SUCKER_REGISTRY,
104
+ address(LOANS_CONTRACT)
105
+ );
106
+
95
107
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
96
108
  jbController(),
97
109
  SUCKER_REGISTRY,
@@ -100,8 +112,10 @@ contract TestEmptyBuybackSpecs is TestBaseWorkflow {
100
112
  PUBLISHER,
101
113
  IJBBuybackHookRegistry(address(MOCK_BUYBACK_MINT_PATH)),
102
114
  address(LOANS_CONTRACT),
103
- TRUSTED_FORWARDER
115
+ TRUSTED_FORWARDER,
116
+ address(REV_OWNER)
104
117
  );
118
+
105
119
  vm.prank(multisig());
106
120
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
107
121
  }
@@ -260,13 +274,13 @@ contract TestEmptyBuybackSpecs is TestBaseWorkflow {
260
274
  metadata: ""
261
275
  });
262
276
 
263
- (uint256 weight, JBPayHookSpecification[] memory specs) = REV_DEPLOYER.beforePayRecordedWith(context);
277
+ (uint256 weight, JBPayHookSpecification[] memory specs) = REV_OWNER.beforePayRecordedWith(context);
264
278
 
265
279
  assertEq(weight, context.weight, "Weight should pass through from buyback hook");
266
280
  assertEq(specs.length, 1, "Should return only the 721 hook spec when buyback hook returns empty");
267
281
  assertEq(
268
282
  address(specs[0].hook),
269
- address(REV_DEPLOYER.tiered721HookOf(revnetId)),
283
+ address(REV_OWNER.tiered721HookOf(revnetId)),
270
284
  "Spec hook should be the revnet's 721 hook"
271
285
  );
272
286
  }
@@ -38,6 +38,8 @@ import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
38
38
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
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
+ import {REVOwner} from "../src/REVOwner.sol";
42
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
41
43
 
42
44
  /// @notice Tests showing that flash loan surplus manipulation is economically unprofitable.
43
45
  contract TestFlashLoanSurplus is TestBaseWorkflow {
@@ -49,6 +51,8 @@ contract TestFlashLoanSurplus 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;
@@ -104,6 +108,14 @@ contract TestFlashLoanSurplus 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,10 @@ contract TestFlashLoanSurplus 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
+
117
131
  vm.prank(multisig());
118
132
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
119
133
  _deployFeeProject();
@@ -38,6 +38,8 @@ import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBefor
38
38
  import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
39
39
  import {JBTokenAmount} from "@bananapus/core-v6/src/structs/JBTokenAmount.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 Tests for PR #22: fix/c2-hook-array-oob
43
45
  /// Verifies that the fix for the hook array out-of-bounds bug works correctly.
@@ -51,6 +53,8 @@ contract TestHookArrayOOB 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;
@@ -94,6 +98,14 @@ contract TestHookArrayOOB is TestBaseWorkflow {
94
98
  permit2: permit2(),
95
99
  trustedForwarder: TRUSTED_FORWARDER
96
100
  });
101
+ REV_OWNER = new REVOwner(
102
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
103
+ jbDirectory(),
104
+ FEE_PROJECT_ID,
105
+ SUCKER_REGISTRY,
106
+ address(LOANS_CONTRACT)
107
+ );
108
+
97
109
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
98
110
  jbController(),
99
111
  SUCKER_REGISTRY,
@@ -102,8 +114,10 @@ contract TestHookArrayOOB is TestBaseWorkflow {
102
114
  PUBLISHER,
103
115
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
104
116
  address(LOANS_CONTRACT),
105
- TRUSTED_FORWARDER
117
+ TRUSTED_FORWARDER,
118
+ address(REV_OWNER)
106
119
  );
120
+
107
121
  vm.prank(multisig());
108
122
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
109
123
  }
@@ -242,7 +256,7 @@ contract TestHookArrayOOB is TestBaseWorkflow {
242
256
  metadata: ""
243
257
  });
244
258
 
245
- (uint256 weight, JBPayHookSpecification[] memory specs) = REV_DEPLOYER.beforePayRecordedWith(context);
259
+ (uint256 weight, JBPayHookSpecification[] memory specs) = REV_OWNER.beforePayRecordedWith(context);
246
260
 
247
261
  // Every revnet has both the buyback hook and the 721 hook.
248
262
  assertEq(weight, context.weight, "Weight should be the default context weight");
@@ -40,6 +40,8 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
40
40
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
41
41
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
42
42
  import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
43
+ import {REVOwner} from "../src/REVOwner.sol";
44
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
43
45
 
44
46
  /// @notice Tests for PR #10: liquidation behavior documentation and collateral burn mechanics.
45
47
  contract TestLiquidationBehavior is TestBaseWorkflow {
@@ -49,6 +51,8 @@ contract TestLiquidationBehavior 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 TestLiquidationBehavior 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,10 @@ contract TestLiquidationBehavior 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
+
115
129
  vm.prank(multisig());
116
130
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
117
131
  _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 {JBSingleAllowance} from "@bananapus/core-v6/src/structs/JBSingleAllowance.sol";
42
42
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
43
+ import {REVOwner} from "../src/REVOwner.sol";
44
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
43
45
 
44
46
  /// @notice Tests for loan source rotation: verify behavior when loans are taken from different sources (tokens)
45
47
  /// and that existing loans remain valid and repayable after new sources are introduced.
@@ -50,6 +52,8 @@ contract TestLoanSourceRotation 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;
@@ -111,6 +115,14 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
111
115
  trustedForwarder: TRUSTED_FORWARDER
112
116
  });
113
117
 
118
+ REV_OWNER = new REVOwner(
119
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
120
+ jbDirectory(),
121
+ FEE_PROJECT_ID,
122
+ SUCKER_REGISTRY,
123
+ address(LOANS_CONTRACT)
124
+ );
125
+
114
126
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
115
127
  jbController(),
116
128
  SUCKER_REGISTRY,
@@ -119,7 +131,8 @@ contract TestLoanSourceRotation is TestBaseWorkflow {
119
131
  PUBLISHER,
120
132
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
121
133
  address(LOANS_CONTRACT),
122
- TRUSTED_FORWARDER
134
+ TRUSTED_FORWARDER,
135
+ address(REV_OWNER)
123
136
  );
124
137
 
125
138
  vm.prank(multisig());
@@ -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
  struct FeeProjectConfig {
42
44
  REVConfig configuration;
@@ -54,6 +56,8 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
54
56
  // forge-lint: disable-next-line(mixed-case-variable)
55
57
  REVDeployer REV_DEPLOYER;
56
58
  // forge-lint: disable-next-line(mixed-case-variable)
59
+ REVOwner REV_OWNER;
60
+ // forge-lint: disable-next-line(mixed-case-variable)
57
61
  JB721TiersHook EXAMPLE_HOOK;
58
62
  // forge-lint: disable-next-line(mixed-case-variable)
59
63
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -214,6 +218,14 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
214
218
  trustedForwarder: TRUSTED_FORWARDER
215
219
  });
216
220
 
221
+ REV_OWNER = new REVOwner(
222
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
223
+ jbDirectory(),
224
+ FEE_PROJECT_ID,
225
+ SUCKER_REGISTRY,
226
+ address(LOANS_CONTRACT)
227
+ );
228
+
217
229
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
218
230
  jbController(),
219
231
  SUCKER_REGISTRY,
@@ -222,7 +234,8 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
222
234
  PUBLISHER,
223
235
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
224
236
  address(LOANS_CONTRACT),
225
- TRUSTED_FORWARDER
237
+ TRUSTED_FORWARDER,
238
+ address(REV_OWNER)
226
239
  );
227
240
 
228
241
  // Approve the deployer to configure the fee project.
@@ -293,13 +306,13 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
293
306
 
294
307
  /// @notice Verify the deployer actually set a cash out delay for the delayed revnet.
295
308
  function test_delayedRevnet_hasCashOutDelay() public view {
296
- uint256 cashOutDelay = REV_DEPLOYER.cashOutDelayOf(DELAYED_REVNET_ID);
309
+ uint256 cashOutDelay = REV_OWNER.cashOutDelayOf(DELAYED_REVNET_ID);
297
310
  assertGt(cashOutDelay, block.timestamp, "Cash out delay should be in the future");
298
311
  }
299
312
 
300
313
  /// @notice Verify the normal revnet has no cash out delay.
301
314
  function test_normalRevnet_noCashOutDelay() public view {
302
- uint256 cashOutDelay = REV_DEPLOYER.cashOutDelayOf(NORMAL_REVNET_ID);
315
+ uint256 cashOutDelay = REV_OWNER.cashOutDelayOf(NORMAL_REVNET_ID);
303
316
  assertEq(cashOutDelay, 0, "Normal revnet should have no cash out delay");
304
317
  }
305
318
 
@@ -327,7 +340,7 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
327
340
  REVLoanSource memory source = REVLoanSource({token: JBConstants.NATIVE_TOKEN, terminal: jbMultiTerminal()});
328
341
 
329
342
  // Attempt to borrow — should revert with CashOutDelayNotFinished.
330
- uint256 cashOutDelay = REV_DEPLOYER.cashOutDelayOf(DELAYED_REVNET_ID);
343
+ uint256 cashOutDelay = REV_OWNER.cashOutDelayOf(DELAYED_REVNET_ID);
331
344
  vm.expectRevert(
332
345
  abi.encodeWithSelector(REVLoans.REVLoans_CashOutDelayNotFinished.selector, cashOutDelay, block.timestamp)
333
346
  );
@@ -429,7 +442,7 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
429
442
  uint256 tokenCount = _payAndGetTokens(DELAYED_REVNET_ID, 1 ether);
430
443
 
431
444
  // Warp to exactly the delay timestamp (not past it).
432
- uint256 cashOutDelay = REV_DEPLOYER.cashOutDelayOf(DELAYED_REVNET_ID);
445
+ uint256 cashOutDelay = REV_OWNER.cashOutDelayOf(DELAYED_REVNET_ID);
433
446
  vm.warp(cashOutDelay);
434
447
 
435
448
  // borrowableAmountFrom should still return 0 (cashOutDelay > block.timestamp is false, but == is not >).
@@ -446,7 +459,7 @@ contract TestLoansCashOutDelay is TestBaseWorkflow {
446
459
  uint256 tokenCount = _payAndGetTokens(DELAYED_REVNET_ID, 1 ether);
447
460
 
448
461
  // Warp to 1 second before the delay expires.
449
- uint256 cashOutDelay = REV_DEPLOYER.cashOutDelayOf(DELAYED_REVNET_ID);
462
+ uint256 cashOutDelay = REV_OWNER.cashOutDelayOf(DELAYED_REVNET_ID);
450
463
  vm.warp(cashOutDelay - 1);
451
464
 
452
465
  // borrowableAmountFrom should return 0.
@@ -35,6 +35,8 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
35
35
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
36
36
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
37
37
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
38
+ import {REVOwner} from "../src/REVOwner.sol";
39
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
38
40
 
39
41
  /// @notice Long-tail economic simulation: run a revnet through multiple stage transitions with many payments
40
42
  /// and cash outs, verifying value conservation and bonding curve consistency.
@@ -45,6 +47,8 @@ contract TestLongTailEconomics is TestBaseWorkflow {
45
47
  // forge-lint: disable-next-line(mixed-case-variable)
46
48
  REVDeployer REV_DEPLOYER;
47
49
  // forge-lint: disable-next-line(mixed-case-variable)
50
+ REVOwner REV_OWNER;
51
+ // forge-lint: disable-next-line(mixed-case-variable)
48
52
  JB721TiersHook EXAMPLE_HOOK;
49
53
  // forge-lint: disable-next-line(mixed-case-variable)
50
54
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -104,6 +108,14 @@ contract TestLongTailEconomics is TestBaseWorkflow {
104
108
  trustedForwarder: TRUSTED_FORWARDER
105
109
  });
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,7 +124,8 @@ contract TestLongTailEconomics 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
  );
117
130
 
118
131
  vm.prank(multisig());
@@ -40,6 +40,8 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
40
40
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
41
41
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
42
42
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
43
+ import {REVOwner} from "../src/REVOwner.sol";
44
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
43
45
 
44
46
  struct FeeProjectConfig {
45
47
  REVConfig configuration;
@@ -56,6 +58,8 @@ contract TestLowFindings is TestBaseWorkflow {
56
58
  // forge-lint: disable-next-line(mixed-case-variable)
57
59
  REVDeployer REV_DEPLOYER;
58
60
  // forge-lint: disable-next-line(mixed-case-variable)
61
+ REVOwner REV_OWNER;
62
+ // forge-lint: disable-next-line(mixed-case-variable)
59
63
  JB721TiersHook EXAMPLE_HOOK;
60
64
  // forge-lint: disable-next-line(mixed-case-variable)
61
65
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -293,6 +297,14 @@ contract TestLowFindings is TestBaseWorkflow {
293
297
  trustedForwarder: TRUSTED_FORWARDER
294
298
  });
295
299
 
300
+ REV_OWNER = new REVOwner(
301
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
302
+ jbDirectory(),
303
+ FEE_PROJECT_ID,
304
+ SUCKER_REGISTRY,
305
+ address(LOANS_CONTRACT)
306
+ );
307
+
296
308
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
297
309
  jbController(),
298
310
  SUCKER_REGISTRY,
@@ -301,7 +313,8 @@ contract TestLowFindings is TestBaseWorkflow {
301
313
  PUBLISHER,
302
314
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
303
315
  address(LOANS_CONTRACT),
304
- TRUSTED_FORWARDER
316
+ TRUSTED_FORWARDER,
317
+ address(REV_OWNER)
305
318
  );
306
319
 
307
320
  // Deploy fee project.
@@ -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 Tests for PR #32: liquidation boundary, reallocate msg.value, and decimal normalization fixes.
43
45
  contract TestMixedFixes is TestBaseWorkflow {
@@ -47,6 +49,8 @@ contract TestMixedFixes is TestBaseWorkflow {
47
49
  // forge-lint: disable-next-line(mixed-case-variable)
48
50
  REVDeployer REV_DEPLOYER;
49
51
  // forge-lint: disable-next-line(mixed-case-variable)
52
+ REVOwner REV_OWNER;
53
+ // forge-lint: disable-next-line(mixed-case-variable)
50
54
  JB721TiersHook EXAMPLE_HOOK;
51
55
  // forge-lint: disable-next-line(mixed-case-variable)
52
56
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -100,6 +104,14 @@ contract TestMixedFixes is TestBaseWorkflow {
100
104
  permit2: permit2(),
101
105
  trustedForwarder: TRUSTED_FORWARDER
102
106
  });
107
+ REV_OWNER = new REVOwner(
108
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
109
+ jbDirectory(),
110
+ FEE_PROJECT_ID,
111
+ SUCKER_REGISTRY,
112
+ address(LOANS_CONTRACT)
113
+ );
114
+
103
115
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
104
116
  jbController(),
105
117
  SUCKER_REGISTRY,
@@ -108,8 +120,10 @@ contract TestMixedFixes is TestBaseWorkflow {
108
120
  PUBLISHER,
109
121
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
110
122
  address(LOANS_CONTRACT),
111
- TRUSTED_FORWARDER
123
+ TRUSTED_FORWARDER,
124
+ address(REV_OWNER)
112
125
  );
126
+
113
127
  vm.prank(multisig());
114
128
  jbProjects().approve(address(REV_DEPLOYER), FEE_PROJECT_ID);
115
129
  _deployFeeProject();
@@ -45,6 +45,8 @@ import {IAllowanceTransfer} from "@uniswap/permit2/src/interfaces/IAllowanceTran
45
45
  import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
46
46
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
47
47
  import {JBFees} from "@bananapus/core-v6/src/libraries/JBFees.sol";
48
+ import {REVOwner} from "../src/REVOwner.sol";
49
+ import {IREVDeployer} from "../src/interfaces/IREVDeployer.sol";
48
50
 
49
51
  struct Permit2ProjectConfig {
50
52
  REVConfig configuration;
@@ -64,6 +66,8 @@ contract TestPermit2Signatures is TestBaseWorkflow {
64
66
  // forge-lint: disable-next-line(mixed-case-variable)
65
67
  REVDeployer REV_DEPLOYER;
66
68
  // forge-lint: disable-next-line(mixed-case-variable)
69
+ REVOwner REV_OWNER;
70
+ // forge-lint: disable-next-line(mixed-case-variable)
67
71
  JB721TiersHook EXAMPLE_HOOK;
68
72
  // forge-lint: disable-next-line(mixed-case-variable)
69
73
  IJB721TiersHookDeployer HOOK_DEPLOYER;
@@ -261,6 +265,14 @@ contract TestPermit2Signatures is TestBaseWorkflow {
261
265
  trustedForwarder: TRUSTED_FORWARDER
262
266
  });
263
267
 
268
+ REV_OWNER = new REVOwner(
269
+ IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
270
+ jbDirectory(),
271
+ FEE_PROJECT_ID,
272
+ SUCKER_REGISTRY,
273
+ address(LOANS_CONTRACT)
274
+ );
275
+
264
276
  REV_DEPLOYER = new REVDeployer{salt: REV_DEPLOYER_SALT}(
265
277
  jbController(),
266
278
  SUCKER_REGISTRY,
@@ -269,7 +281,8 @@ contract TestPermit2Signatures is TestBaseWorkflow {
269
281
  PUBLISHER,
270
282
  IJBBuybackHookRegistry(address(MOCK_BUYBACK)),
271
283
  address(LOANS_CONTRACT),
272
- TRUSTED_FORWARDER
284
+ TRUSTED_FORWARDER,
285
+ address(REV_OWNER)
273
286
  );
274
287
 
275
288
  // Approve the basic deployer to configure the project.