@rev-net/core-v6 0.0.12 → 0.0.13

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 (78) hide show
  1. package/AUDIT_INSTRUCTIONS.md +295 -0
  2. package/CHANGE_LOG.md +316 -0
  3. package/README.md +2 -2
  4. package/RISKS.md +180 -35
  5. package/SKILLS.md +1 -1
  6. package/USER_JOURNEYS.md +489 -0
  7. package/package.json +9 -9
  8. package/script/Deploy.s.sol +40 -6
  9. package/script/helpers/RevnetCoreDeploymentLib.sol +7 -1
  10. package/src/REVDeployer.sol +63 -47
  11. package/src/REVLoans.sol +51 -15
  12. package/src/interfaces/IREVDeployer.sol +0 -1
  13. package/src/structs/REV721TiersHookFlags.sol +1 -0
  14. package/src/structs/REVAutoIssuance.sol +1 -0
  15. package/src/structs/REVBaseline721HookConfig.sol +1 -0
  16. package/src/structs/REVConfig.sol +1 -0
  17. package/src/structs/REVCroptopAllowedPost.sol +1 -0
  18. package/src/structs/REVDeploy721TiersHookConfig.sol +1 -0
  19. package/src/structs/REVDescription.sol +1 -0
  20. package/src/structs/REVLoan.sol +1 -0
  21. package/src/structs/REVLoanSource.sol +1 -0
  22. package/src/structs/REVStageConfig.sol +1 -0
  23. package/src/structs/REVSuckerDeploymentConfig.sol +1 -0
  24. package/test/REV.integrations.t.sol +132 -12
  25. package/test/REVAutoIssuanceFuzz.t.sol +23 -3
  26. package/test/REVDeployerRegressions.t.sol +35 -4
  27. package/test/REVInvincibility.t.sol +58 -8
  28. package/test/REVInvincibilityHandler.sol +29 -0
  29. package/test/REVLifecycle.t.sol +28 -3
  30. package/test/REVLoans.invariants.t.sol +52 -5
  31. package/test/REVLoansAttacks.t.sol +43 -5
  32. package/test/REVLoansFeeRecovery.t.sol +50 -11
  33. package/test/REVLoansFindings.t.sol +27 -3
  34. package/test/REVLoansRegressions.t.sol +25 -3
  35. package/test/REVLoansSourceFeeRecovery.t.sol +491 -0
  36. package/test/REVLoansSourced.t.sol +56 -7
  37. package/test/REVLoansUnSourced.t.sol +49 -5
  38. package/test/TestBurnHeldTokens.t.sol +32 -5
  39. package/test/TestCEIPattern.t.sol +26 -2
  40. package/test/TestCashOutCallerValidation.t.sol +30 -4
  41. package/test/TestConversionDocumentation.t.sol +26 -5
  42. package/test/TestCrossCurrencyReclaim.t.sol +584 -0
  43. package/test/TestCrossSourceReallocation.t.sol +26 -2
  44. package/test/TestERC2771MetaTx.t.sol +557 -0
  45. package/test/TestEmptyBuybackSpecs.t.sol +23 -3
  46. package/test/TestFlashLoanSurplus.t.sol +28 -3
  47. package/test/TestHookArrayOOB.t.sol +24 -4
  48. package/test/TestLiquidationBehavior.t.sol +26 -3
  49. package/test/TestLoanSourceRotation.t.sol +525 -0
  50. package/test/TestLongTailEconomics.t.sol +651 -0
  51. package/test/TestLowFindings.t.sol +65 -2
  52. package/test/TestMixedFixes.t.sol +28 -3
  53. package/test/TestPermit2Signatures.t.sol +657 -0
  54. package/test/TestReallocationSandwich.t.sol +384 -0
  55. package/test/TestRevnetRegressions.t.sol +324 -0
  56. package/test/TestSplitWeightAdjustment.t.sol +24 -2
  57. package/test/TestSplitWeightE2E.t.sol +29 -2
  58. package/test/TestSplitWeightFork.t.sol +46 -7
  59. package/test/TestStageTransitionBorrowable.t.sol +24 -2
  60. package/test/TestSwapTerminalPermission.t.sol +23 -3
  61. package/test/TestUint112Overflow.t.sol +28 -2
  62. package/test/TestZeroRepayment.t.sol +26 -2
  63. package/test/fork/ForkTestBase.sol +46 -3
  64. package/test/fork/TestCashOutFork.t.sol +1 -1
  65. package/test/fork/TestLoanBorrowFork.t.sol +1 -0
  66. package/test/fork/TestLoanCrossRulesetFork.t.sol +3 -1
  67. package/test/fork/TestLoanLiquidationFork.t.sol +1 -0
  68. package/test/fork/TestLoanReallocateFork.t.sol +1 -0
  69. package/test/fork/TestLoanRepayFork.t.sol +1 -0
  70. package/test/fork/TestLoanTransferFork.t.sol +133 -0
  71. package/test/fork/TestSplitWeightFork.t.sol +3 -0
  72. package/test/helpers/REVEmpty721Config.sol +1 -0
  73. package/test/mock/MockBuybackDataHook.sol +1 -0
  74. package/test/regression/TestBurnPermissionRequired.t.sol +267 -0
  75. package/test/regression/TestCrossRevnetLiquidation.t.sol +228 -0
  76. package/test/regression/TestCumulativeLoanCounter.t.sol +27 -4
  77. package/test/regression/TestLiquidateGapHandling.t.sol +29 -4
  78. package/test/regression/TestZeroPriceFeed.t.sol +396 -0
@@ -1,11 +1,15 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
+ // forge-lint: disable-next-line(unaliased-plain-import)
4
5
  import "forge-std/Test.sol";
6
+ // forge-lint: disable-next-line(unaliased-plain-import)
5
7
  import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
6
8
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
9
+ // forge-lint: disable-next-line(unused-import)
7
10
  import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
8
11
  import {mulDiv} from "@prb/math/src/Common.sol";
12
+ // forge-lint: disable-next-line(unused-import)
9
13
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
10
14
 
11
15
  import {IREVLoans} from "../src/interfaces/IREVLoans.sol";
@@ -20,24 +24,41 @@ contract REVInvincibilityHandler is JBTest {
20
24
  // =========================================================================
21
25
  // Ghost variables
22
26
  // =========================================================================
27
+ // forge-lint: disable-next-line(mixed-case-variable)
23
28
  uint256 public COLLATERAL_SUM;
29
+ // forge-lint: disable-next-line(mixed-case-variable)
24
30
  uint256 public COLLATERAL_RETURNED;
31
+ // forge-lint: disable-next-line(mixed-case-variable)
25
32
  uint256 public BORROWED_SUM;
33
+ // forge-lint: disable-next-line(mixed-case-variable)
26
34
  uint256 public REPAID_SUM;
35
+ // forge-lint: disable-next-line(mixed-case-variable)
27
36
  uint256 public PAID_IN_SUM;
37
+ // forge-lint: disable-next-line(mixed-case-variable)
28
38
  uint256 public CASHED_OUT_SUM;
39
+ // forge-lint: disable-next-line(mixed-case-variable)
29
40
  uint256 public ADDED_TO_BALANCE_SUM;
30
41
 
31
42
  // Per-operation call counts
43
+ // forge-lint: disable-next-line(mixed-case-variable)
32
44
  uint256 public callCount_payAndBorrow;
45
+ // forge-lint: disable-next-line(mixed-case-variable)
33
46
  uint256 public callCount_repayLoan;
47
+ // forge-lint: disable-next-line(mixed-case-variable)
34
48
  uint256 public callCount_reallocateCollateral;
49
+ // forge-lint: disable-next-line(mixed-case-variable)
35
50
  uint256 public callCount_liquidateLoans;
51
+ // forge-lint: disable-next-line(mixed-case-variable)
36
52
  uint256 public callCount_advanceTime;
53
+ // forge-lint: disable-next-line(mixed-case-variable)
37
54
  uint256 public callCount_payInto;
55
+ // forge-lint: disable-next-line(mixed-case-variable)
38
56
  uint256 public callCount_cashOut;
57
+ // forge-lint: disable-next-line(mixed-case-variable)
39
58
  uint256 public callCount_addToBalance;
59
+ // forge-lint: disable-next-line(mixed-case-variable)
40
60
  uint256 public callCount_sendReservedTokens;
61
+ // forge-lint: disable-next-line(mixed-case-variable)
41
62
  uint256 public callCount_changeStage;
42
63
 
43
64
  // Fee project tracking
@@ -46,13 +67,21 @@ contract REVInvincibilityHandler is JBTest {
46
67
  // =========================================================================
47
68
  // Dependencies
48
69
  // =========================================================================
70
+ // forge-lint: disable-next-line(mixed-case-variable)
49
71
  IJBMultiTerminal public TERMINAL;
72
+ // forge-lint: disable-next-line(mixed-case-variable)
50
73
  IREVLoans public LOANS;
74
+ // forge-lint: disable-next-line(mixed-case-variable)
51
75
  IJBPermissions public PERMS;
76
+ // forge-lint: disable-next-line(mixed-case-variable)
52
77
  IJBTokens public TOKENS;
78
+ // forge-lint: disable-next-line(mixed-case-variable)
53
79
  IJBController public CTRL;
80
+ // forge-lint: disable-next-line(mixed-case-variable)
54
81
  uint256 public REVNET_ID;
82
+ // forge-lint: disable-next-line(mixed-case-variable)
55
83
  uint256 public FEE_PROJECT_ID;
84
+ // forge-lint: disable-next-line(mixed-case-variable)
56
85
  address public USER;
57
86
 
58
87
  // Stage boundaries (for changeStage)
@@ -1,23 +1,31 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
+ // forge-lint: disable-next-line(unaliased-plain-import)
4
5
  import "forge-std/Test.sol";
6
+ // forge-lint: disable-next-line(unaliased-plain-import)
5
7
  import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
6
- import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
8
+ // import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
9
+ // forge-lint: disable-next-line(unaliased-plain-import)
7
10
  import /* {*} from */ "./../src/REVDeployer.sol";
11
+ // forge-lint: disable-next-line(unaliased-plain-import)
8
12
  import "@croptop/core-v6/src/CTPublisher.sol";
9
13
  import {MockBuybackDataHook} from "./mock/MockBuybackDataHook.sol";
10
14
 
15
+ // forge-lint: disable-next-line(unaliased-plain-import)
11
16
  import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
17
+ // forge-lint: disable-next-line(unaliased-plain-import)
12
18
  import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
19
+ // forge-lint: disable-next-line(unaliased-plain-import)
13
20
  import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
21
+ // forge-lint: disable-next-line(unaliased-plain-import)
14
22
  import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
23
+ // forge-lint: disable-next-line(unaliased-plain-import)
15
24
  import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
16
25
 
17
26
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
18
27
  import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
19
28
  import {REVLoans} from "../src/REVLoans.sol";
20
- import {REVLoan} from "../src/structs/REVLoan.sol";
21
29
  import {REVStageConfig, REVAutoIssuance} from "../src/structs/REVStageConfig.sol";
22
30
  import {REVDescription} from "../src/structs/REVDescription.sol";
23
31
  import {IREVLoans} from "./../src/interfaces/IREVLoans.sol";
@@ -29,29 +37,44 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
29
37
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
30
38
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
31
39
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
32
- import {REVCroptopAllowedPost} from "../src/structs/REVCroptopAllowedPost.sol";
33
40
 
34
41
  /// @notice Full revnet lifecycle E2E: deploy 3-stage -> pay -> advance stages -> cash out.
35
42
  contract REVLifecycle_Local is TestBaseWorkflow {
43
+ // forge-lint: disable-next-line(mixed-case-variable)
36
44
  bytes32 REV_DEPLOYER_SALT = "REVDeployer";
45
+ // forge-lint: disable-next-line(mixed-case-variable)
37
46
  bytes32 ERC20_SALT = "REV_TOKEN";
38
47
 
48
+ // forge-lint: disable-next-line(mixed-case-variable)
39
49
  REVDeployer REV_DEPLOYER;
50
+ // forge-lint: disable-next-line(mixed-case-variable)
40
51
  JB721TiersHook EXAMPLE_HOOK;
52
+ // forge-lint: disable-next-line(mixed-case-variable)
41
53
  IJB721TiersHookDeployer HOOK_DEPLOYER;
54
+ // forge-lint: disable-next-line(mixed-case-variable)
42
55
  IJB721TiersHookStore HOOK_STORE;
56
+ // forge-lint: disable-next-line(mixed-case-variable)
43
57
  IJBAddressRegistry ADDRESS_REGISTRY;
58
+ // forge-lint: disable-next-line(mixed-case-variable)
44
59
  IREVLoans LOANS_CONTRACT;
60
+ // forge-lint: disable-next-line(mixed-case-variable)
45
61
  IJBSuckerRegistry SUCKER_REGISTRY;
62
+ // forge-lint: disable-next-line(mixed-case-variable)
46
63
  CTPublisher PUBLISHER;
64
+ // forge-lint: disable-next-line(mixed-case-variable)
47
65
  MockBuybackDataHook MOCK_BUYBACK;
48
66
 
67
+ // forge-lint: disable-next-line(mixed-case-variable)
49
68
  uint256 FEE_PROJECT_ID;
69
+ // forge-lint: disable-next-line(mixed-case-variable)
50
70
  uint256 REVNET_ID;
51
71
 
72
+ // forge-lint: disable-next-line(mixed-case-variable)
52
73
  address USER1 = makeAddr("user1");
74
+ // forge-lint: disable-next-line(mixed-case-variable)
53
75
  address USER2 = makeAddr("user2");
54
76
 
77
+ // forge-lint: disable-next-line(mixed-case-variable)
55
78
  uint256 DECIMAL_MULTIPLIER = 10 ** 18;
56
79
 
57
80
  address private constant TRUSTED_FORWARDER = 0xB2b5841DBeF766d4b521221732F9B618fCf34A87;
@@ -124,6 +147,7 @@ contract REVLifecycle_Local is TestBaseWorkflow {
124
147
  autoIssuances: new REVAutoIssuance[](0),
125
148
  splitPercent: 0,
126
149
  splits: splits,
150
+ // forge-lint: disable-next-line(unsafe-typecast)
127
151
  initialIssuance: uint112(1000 * DECIMAL_MULTIPLIER),
128
152
  issuanceCutFrequency: 90 days,
129
153
  issuanceCutPercent: JBConstants.MAX_WEIGHT_CUT_PERCENT / 2,
@@ -158,6 +182,7 @@ contract REVLifecycle_Local is TestBaseWorkflow {
158
182
  });
159
183
 
160
184
  REVConfig memory revnetConfiguration = REVConfig({
185
+ // forge-lint: disable-next-line(named-struct-fields)
161
186
  description: REVDescription("Lifecycle", "LIFE", "ipfs://lifecycle", "LIFE_TOKEN"),
162
187
  baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
163
188
  splitOperator: multisig(),
@@ -1,24 +1,32 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
+ // forge-lint: disable-next-line(unaliased-plain-import)
4
5
  import "forge-std/Test.sol";
5
6
  import {StdInvariant} from "forge-std/StdInvariant.sol";
7
+ // forge-lint: disable-next-line(unaliased-plain-import)
6
8
  import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
7
- import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
9
+ // import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
10
+ // forge-lint: disable-next-line(unaliased-plain-import)
8
11
  import /* {*} from */ "./../src/REVDeployer.sol";
12
+ // forge-lint: disable-next-line(unaliased-plain-import)
9
13
  import /* {*} from */ "./../src/REVLoans.sol";
14
+ // forge-lint: disable-next-line(unaliased-plain-import)
10
15
  import "@croptop/core-v6/src/CTPublisher.sol";
11
16
  import {MockBuybackDataHook} from "./mock/MockBuybackDataHook.sol";
12
17
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
13
- import {REVCroptopAllowedPost} from "../src/structs/REVCroptopAllowedPost.sol";
14
18
 
19
+ // forge-lint: disable-next-line(unaliased-plain-import)
15
20
  import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
21
+ // forge-lint: disable-next-line(unaliased-plain-import)
16
22
  import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
23
+ // forge-lint: disable-next-line(unaliased-plain-import)
17
24
  import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
25
+ // forge-lint: disable-next-line(unaliased-plain-import)
18
26
  import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
27
+ // forge-lint: disable-next-line(unaliased-plain-import)
19
28
  import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
20
29
 
21
- import {JBCashOuts} from "@bananapus/core-v6/src/libraries/JBCashOuts.sol";
22
30
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
23
31
  import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
24
32
  import {REVLoans} from "../src/REVLoans.sol";
@@ -42,17 +50,28 @@ struct FeeProjectConfig {
42
50
  }
43
51
 
44
52
  contract REVLoansCallHandler is JBTest {
53
+ // forge-lint: disable-next-line(mixed-case-variable)
45
54
  uint256 public COLLATERAL_SUM;
55
+ // forge-lint: disable-next-line(mixed-case-variable)
46
56
  uint256 public COLLATERAL_RETURNED;
57
+ // forge-lint: disable-next-line(mixed-case-variable)
47
58
  uint256 public BORROWED_SUM;
59
+ // forge-lint: disable-next-line(mixed-case-variable)
48
60
  uint256 public RUNS;
61
+ // forge-lint: disable-next-line(mixed-case-variable)
49
62
  uint256 REVNET_ID;
63
+ // forge-lint: disable-next-line(mixed-case-variable)
50
64
  uint256 LAST_LOAN_MODIFIED;
65
+ // forge-lint: disable-next-line(mixed-case-variable)
51
66
  address USER;
52
67
 
68
+ // forge-lint: disable-next-line(mixed-case-variable)
53
69
  IJBMultiTerminal TERMINAL;
70
+ // forge-lint: disable-next-line(mixed-case-variable)
54
71
  IREVLoans LOANS;
72
+ // forge-lint: disable-next-line(mixed-case-variable)
55
73
  IJBPermissions PERMS;
74
+ // forge-lint: disable-next-line(mixed-case-variable)
56
75
  IJBTokens TOKENS;
57
76
 
58
77
  constructor(
@@ -260,34 +279,50 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
260
279
  using JBRulesetMetadataResolver for JBRuleset;
261
280
 
262
281
  /// @notice the salts that are used to deploy the contracts.
282
+ // forge-lint: disable-next-line(mixed-case-variable)
263
283
  bytes32 REV_DEPLOYER_SALT = "REVDeployer";
284
+ // forge-lint: disable-next-line(mixed-case-variable)
264
285
  bytes32 ERC20_SALT = "REV_TOKEN";
265
286
 
266
287
  // Handlers
288
+ // forge-lint: disable-next-line(mixed-case-variable)
267
289
  REVLoansCallHandler PAY_HANDLER;
268
290
 
291
+ // forge-lint: disable-next-line(mixed-case-variable)
269
292
  REVDeployer REV_DEPLOYER;
293
+ // forge-lint: disable-next-line(mixed-case-variable)
270
294
  JB721TiersHook EXAMPLE_HOOK;
271
295
 
272
296
  /// @notice Deploys tiered ERC-721 hooks for revnets.
297
+ // forge-lint: disable-next-line(mixed-case-variable)
273
298
  IJB721TiersHookDeployer HOOK_DEPLOYER;
299
+ // forge-lint: disable-next-line(mixed-case-variable)
274
300
  IJB721TiersHookStore HOOK_STORE;
301
+ // forge-lint: disable-next-line(mixed-case-variable)
275
302
  IJBAddressRegistry ADDRESS_REGISTRY;
276
303
 
304
+ // forge-lint: disable-next-line(mixed-case-variable)
277
305
  IREVLoans LOANS_CONTRACT;
278
306
 
279
307
  /// @notice Deploys and tracks suckers for revnets.
308
+ // forge-lint: disable-next-line(mixed-case-variable)
280
309
  IJBSuckerRegistry SUCKER_REGISTRY;
281
310
 
311
+ // forge-lint: disable-next-line(mixed-case-variable)
282
312
  CTPublisher PUBLISHER;
313
+ // forge-lint: disable-next-line(mixed-case-variable)
283
314
  MockBuybackDataHook MOCK_BUYBACK;
284
315
 
285
316
  // When the second project is deployed, track the block.timestamp.
317
+ // forge-lint: disable-next-line(mixed-case-variable)
286
318
  uint256 INITIAL_TIMESTAMP;
287
319
 
320
+ // forge-lint: disable-next-line(mixed-case-variable)
288
321
  uint256 FEE_PROJECT_ID;
322
+ // forge-lint: disable-next-line(mixed-case-variable)
289
323
  uint256 REVNET_ID;
290
324
 
325
+ // forge-lint: disable-next-line(mixed-case-variable)
291
326
  address USER = makeAddr("user");
292
327
 
293
328
  /// @notice The address that is allowed to forward calls.
@@ -324,7 +359,11 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
324
359
  {
325
360
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
326
361
  issuanceConfs[0] = REVAutoIssuance({
327
- chainId: uint32(block.chainid), count: uint104(70_000 * decimalMultiplier), beneficiary: multisig()
362
+ // forge-lint: disable-next-line(unsafe-typecast)
363
+ chainId: uint32(block.chainid),
364
+ // forge-lint: disable-next-line(unsafe-typecast)
365
+ count: uint104(70_000 * decimalMultiplier),
366
+ beneficiary: multisig()
328
367
  });
329
368
 
330
369
  stageConfigurations[0] = REVStageConfig({
@@ -332,6 +371,7 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
332
371
  autoIssuances: issuanceConfs,
333
372
  splitPercent: 2000, // 20%
334
373
  splits: splits,
374
+ // forge-lint: disable-next-line(unsafe-typecast)
335
375
  initialIssuance: uint112(1000 * decimalMultiplier),
336
376
  issuanceCutFrequency: 90 days,
337
377
  issuanceCutPercent: JBConstants.MAX_WEIGHT_CUT_PERCENT / 2,
@@ -366,6 +406,7 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
366
406
 
367
407
  // The project's revnet configuration
368
408
  REVConfig memory revnetConfiguration = REVConfig({
409
+ // forge-lint: disable-next-line(named-struct-fields)
369
410
  description: REVDescription(name, symbol, projectUri, ERC20_SALT),
370
411
  baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
371
412
  splitOperator: multisig(),
@@ -412,7 +453,11 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
412
453
  {
413
454
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
414
455
  issuanceConfs[0] = REVAutoIssuance({
415
- chainId: uint32(block.chainid), count: uint104(70_000 * decimalMultiplier), beneficiary: multisig()
456
+ // forge-lint: disable-next-line(unsafe-typecast)
457
+ chainId: uint32(block.chainid),
458
+ // forge-lint: disable-next-line(unsafe-typecast)
459
+ count: uint104(70_000 * decimalMultiplier),
460
+ beneficiary: multisig()
416
461
  });
417
462
 
418
463
  stageConfigurations[0] = REVStageConfig({
@@ -420,6 +465,7 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
420
465
  autoIssuances: issuanceConfs,
421
466
  splitPercent: 2000, // 20%
422
467
  splits: splits,
468
+ // forge-lint: disable-next-line(unsafe-typecast)
423
469
  initialIssuance: uint112(1000 * decimalMultiplier),
424
470
  issuanceCutFrequency: 90 days,
425
471
  issuanceCutPercent: JBConstants.MAX_WEIGHT_CUT_PERCENT / 2,
@@ -454,6 +500,7 @@ contract InvariantREVLoansTests is StdInvariant, TestBaseWorkflow {
454
500
 
455
501
  // The project's revnet configuration
456
502
  REVConfig memory revnetConfiguration = REVConfig({
503
+ // forge-lint: disable-next-line(named-struct-fields)
457
504
  description: REVDescription(name, symbol, projectUri, "NANA_TOKEN"),
458
505
  baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
459
506
  splitOperator: multisig(),
@@ -1,17 +1,26 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
+ // forge-lint: disable-next-line(unaliased-plain-import)
4
5
  import "forge-std/Test.sol";
6
+ // forge-lint: disable-next-line(unaliased-plain-import)
5
7
  import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
6
- import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
8
+ // import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
9
+ // forge-lint: disable-next-line(unaliased-plain-import)
7
10
  import /* {*} from */ "./../src/REVDeployer.sol";
11
+ // forge-lint: disable-next-line(unaliased-plain-import)
8
12
  import "@croptop/core-v6/src/CTPublisher.sol";
9
13
  import {MockBuybackDataHook} from "./mock/MockBuybackDataHook.sol";
10
14
 
15
+ // forge-lint: disable-next-line(unaliased-plain-import)
11
16
  import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
17
+ // forge-lint: disable-next-line(unaliased-plain-import)
12
18
  import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
19
+ // forge-lint: disable-next-line(unaliased-plain-import)
13
20
  import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
21
+ // forge-lint: disable-next-line(unaliased-plain-import)
14
22
  import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
23
+ // forge-lint: disable-next-line(unaliased-plain-import)
15
24
  import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
16
25
 
17
26
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
@@ -32,9 +41,7 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
32
41
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
33
42
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
34
43
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
35
- import {REVCroptopAllowedPost} from "../src/structs/REVCroptopAllowedPost.sol";
36
44
  import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
37
- import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
38
45
 
39
46
  /// @notice A malicious terminal that re-enters REVLoans during fee payment in _adjust().
40
47
  /// @dev Reentrancy during pay() callback in _adjust.
@@ -179,24 +186,40 @@ struct AttackProjectConfig {
179
186
  /// @notice Attack tests for REVLoans covering uint112 truncation, reentrancy,
180
187
  /// collateral race conditions, liquidation edge cases, and fuzz testing.
181
188
  contract REVLoansAttacks is TestBaseWorkflow {
189
+ // forge-lint: disable-next-line(mixed-case-variable)
182
190
  bytes32 REV_DEPLOYER_SALT = "REVDeployer";
191
+ // forge-lint: disable-next-line(mixed-case-variable)
183
192
  bytes32 ERC20_SALT = "REV_TOKEN";
184
193
 
194
+ // forge-lint: disable-next-line(mixed-case-variable)
185
195
  REVDeployer REV_DEPLOYER;
196
+ // forge-lint: disable-next-line(mixed-case-variable)
186
197
  JB721TiersHook EXAMPLE_HOOK;
198
+ // forge-lint: disable-next-line(mixed-case-variable)
187
199
  IJB721TiersHookDeployer HOOK_DEPLOYER;
200
+ // forge-lint: disable-next-line(mixed-case-variable)
188
201
  IJB721TiersHookStore HOOK_STORE;
202
+ // forge-lint: disable-next-line(mixed-case-variable)
189
203
  IJBAddressRegistry ADDRESS_REGISTRY;
204
+ // forge-lint: disable-next-line(mixed-case-variable)
190
205
  IREVLoans LOANS_CONTRACT;
206
+ // forge-lint: disable-next-line(mixed-case-variable)
191
207
  MockERC20 TOKEN;
208
+ // forge-lint: disable-next-line(mixed-case-variable)
192
209
  IJBSuckerRegistry SUCKER_REGISTRY;
210
+ // forge-lint: disable-next-line(mixed-case-variable)
193
211
  CTPublisher PUBLISHER;
212
+ // forge-lint: disable-next-line(mixed-case-variable)
194
213
  MockBuybackDataHook MOCK_BUYBACK;
195
214
 
215
+ // forge-lint: disable-next-line(mixed-case-variable)
196
216
  uint256 FEE_PROJECT_ID;
217
+ // forge-lint: disable-next-line(mixed-case-variable)
197
218
  uint256 REVNET_ID;
198
219
 
220
+ // forge-lint: disable-next-line(mixed-case-variable)
199
221
  address USER = makeAddr("user");
222
+ // forge-lint: disable-next-line(mixed-case-variable)
200
223
  address ATTACKER = makeAddr("attacker");
201
224
 
202
225
  address private constant TRUSTED_FORWARDER = 0xB2b5841DBeF766d4b521221732F9B618fCf34A87;
@@ -226,7 +249,11 @@ contract REVLoansAttacks is TestBaseWorkflow {
226
249
 
227
250
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
228
251
  issuanceConfs[0] = REVAutoIssuance({
229
- chainId: uint32(block.chainid), count: uint104(70_000 * decimalMultiplier), beneficiary: multisig()
252
+ // forge-lint: disable-next-line(unsafe-typecast)
253
+ chainId: uint32(block.chainid),
254
+ // forge-lint: disable-next-line(unsafe-typecast)
255
+ count: uint104(70_000 * decimalMultiplier),
256
+ beneficiary: multisig()
230
257
  });
231
258
 
232
259
  stageConfigurations[0] = REVStageConfig({
@@ -234,6 +261,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
234
261
  autoIssuances: issuanceConfs,
235
262
  splitPercent: 2000,
236
263
  splits: splits,
264
+ // forge-lint: disable-next-line(unsafe-typecast)
237
265
  initialIssuance: uint112(1000 * decimalMultiplier),
238
266
  issuanceCutFrequency: 90 days,
239
267
  issuanceCutPercent: JBConstants.MAX_WEIGHT_CUT_PERCENT / 2,
@@ -242,6 +270,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
242
270
  });
243
271
 
244
272
  REVConfig memory revnetConfiguration = REVConfig({
273
+ // forge-lint: disable-next-line(named-struct-fields)
245
274
  description: REVDescription(name, symbol, projectUri, ERC20_SALT),
246
275
  baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
247
276
  splitOperator: multisig(),
@@ -282,7 +311,11 @@ contract REVLoansAttacks is TestBaseWorkflow {
282
311
  REVStageConfig[] memory stageConfigurations = new REVStageConfig[](1);
283
312
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
284
313
  issuanceConfs[0] = REVAutoIssuance({
285
- chainId: uint32(block.chainid), count: uint104(70_000 * decimalMultiplier), beneficiary: multisig()
314
+ // forge-lint: disable-next-line(unsafe-typecast)
315
+ chainId: uint32(block.chainid),
316
+ // forge-lint: disable-next-line(unsafe-typecast)
317
+ count: uint104(70_000 * decimalMultiplier),
318
+ beneficiary: multisig()
286
319
  });
287
320
 
288
321
  stageConfigurations[0] = REVStageConfig({
@@ -290,6 +323,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
290
323
  autoIssuances: issuanceConfs,
291
324
  splitPercent: 2000,
292
325
  splits: splits,
326
+ // forge-lint: disable-next-line(unsafe-typecast)
293
327
  initialIssuance: uint112(1000 * decimalMultiplier),
294
328
  issuanceCutFrequency: 90 days,
295
329
  issuanceCutPercent: JBConstants.MAX_WEIGHT_CUT_PERCENT / 2,
@@ -298,6 +332,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
298
332
  });
299
333
 
300
334
  REVConfig memory revnetConfiguration = REVConfig({
335
+ // forge-lint: disable-next-line(named-struct-fields)
301
336
  description: REVDescription(name, symbol, projectUri, "NANA_TOKEN"),
302
337
  baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
303
338
  splitOperator: multisig(),
@@ -447,11 +482,13 @@ contract REVLoansAttacks is TestBaseWorkflow {
447
482
  // Now verify that the uint112 cast would truncate if somehow a larger value were used.
448
483
  // We can directly verify the truncation behavior:
449
484
  uint256 overflowValue = uint256(type(uint112).max) + 1;
485
+ // forge-lint: disable-next-line(unsafe-typecast)
450
486
  uint112 truncated = uint112(overflowValue);
451
487
  assertEq(truncated, 0, "uint112 truncation of max+1 should wrap to 0");
452
488
 
453
489
  // And for a value just slightly above max:
454
490
  uint256 slightlyOver = uint256(type(uint112).max) + 1000;
491
+ // forge-lint: disable-next-line(unsafe-typecast)
455
492
  uint112 truncated2 = uint112(slightlyOver);
456
493
  assertEq(truncated2, 999, "uint112 truncation should wrap around");
457
494
  }
@@ -467,6 +504,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
467
504
  uint256 overflowCollateral = maxCollateral + 1;
468
505
 
469
506
  // Direct cast would truncate
507
+ // forge-lint: disable-next-line(unsafe-typecast)
470
508
  uint112 truncated = uint112(overflowCollateral);
471
509
  assertEq(truncated, 0, "Collateral overflow should truncate to 0");
472
510
 
@@ -1,17 +1,26 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
+ // forge-lint: disable-next-line(unaliased-plain-import)
4
5
  import "forge-std/Test.sol";
6
+ // forge-lint: disable-next-line(unaliased-plain-import)
5
7
  import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
6
- import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
8
+ // import /* {*} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
9
+ // forge-lint: disable-next-line(unaliased-plain-import)
7
10
  import /* {*} from */ "./../src/REVDeployer.sol";
11
+ // forge-lint: disable-next-line(unaliased-plain-import)
8
12
  import "@croptop/core-v6/src/CTPublisher.sol";
9
13
  import {MockBuybackDataHook} from "./mock/MockBuybackDataHook.sol";
10
14
 
15
+ // forge-lint: disable-next-line(unaliased-plain-import)
11
16
  import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
17
+ // forge-lint: disable-next-line(unaliased-plain-import)
12
18
  import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
19
+ // forge-lint: disable-next-line(unaliased-plain-import)
13
20
  import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
21
+ // forge-lint: disable-next-line(unaliased-plain-import)
14
22
  import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
23
+ // forge-lint: disable-next-line(unaliased-plain-import)
15
24
  import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
16
25
 
17
26
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
@@ -33,9 +42,7 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
33
42
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
34
43
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
35
44
  import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
36
- import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
37
45
  import {REVEmpty721Config} from "./helpers/REVEmpty721Config.sol";
38
- import {REVCroptopAllowedPost} from "../src/structs/REVCroptopAllowedPost.sol";
39
46
 
40
47
  /// @notice A terminal mock that always reverts on pay(), used to simulate fee payment failure.
41
48
  contract RevertingFeeTerminal is ERC165, IJBPayoutTerminal {
@@ -139,24 +146,40 @@ struct FeeRecoveryProjectConfig {
139
146
  /// @dev When feeTerminal.pay() reverts, the borrower should receive the fee amount back
140
147
  /// instead of losing it. For ERC-20 tokens, the dangling allowance must also be cleaned up.
141
148
  contract REVLoansFeeRecovery is TestBaseWorkflow {
149
+ // forge-lint: disable-next-line(mixed-case-variable)
142
150
  bytes32 REV_DEPLOYER_SALT = "REVDeployer";
151
+ // forge-lint: disable-next-line(mixed-case-variable)
143
152
  bytes32 ERC20_SALT = "REV_TOKEN";
144
153
 
154
+ // forge-lint: disable-next-line(mixed-case-variable)
145
155
  REVDeployer REV_DEPLOYER;
156
+ // forge-lint: disable-next-line(mixed-case-variable)
146
157
  JB721TiersHook EXAMPLE_HOOK;
158
+ // forge-lint: disable-next-line(mixed-case-variable)
147
159
  IJB721TiersHookDeployer HOOK_DEPLOYER;
160
+ // forge-lint: disable-next-line(mixed-case-variable)
148
161
  IJB721TiersHookStore HOOK_STORE;
162
+ // forge-lint: disable-next-line(mixed-case-variable)
149
163
  IJBAddressRegistry ADDRESS_REGISTRY;
164
+ // forge-lint: disable-next-line(mixed-case-variable)
150
165
  IREVLoans LOANS_CONTRACT;
166
+ // forge-lint: disable-next-line(mixed-case-variable)
151
167
  MockERC20 TOKEN;
168
+ // forge-lint: disable-next-line(mixed-case-variable)
152
169
  IJBSuckerRegistry SUCKER_REGISTRY;
170
+ // forge-lint: disable-next-line(mixed-case-variable)
153
171
  CTPublisher PUBLISHER;
172
+ // forge-lint: disable-next-line(mixed-case-variable)
154
173
  MockBuybackDataHook MOCK_BUYBACK;
174
+ // forge-lint: disable-next-line(mixed-case-variable)
155
175
  RevertingFeeTerminal REVERTING_TERMINAL;
156
176
 
177
+ // forge-lint: disable-next-line(mixed-case-variable)
157
178
  uint256 FEE_PROJECT_ID;
179
+ // forge-lint: disable-next-line(mixed-case-variable)
158
180
  uint256 REVNET_ID;
159
181
 
182
+ // forge-lint: disable-next-line(mixed-case-variable)
160
183
  address USER = makeAddr("user");
161
184
  address private constant TRUSTED_FORWARDER = 0xB2b5841DBeF766d4b521221732F9B618fCf34A87;
162
185
 
@@ -182,7 +205,11 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
182
205
 
183
206
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
184
207
  issuanceConfs[0] = REVAutoIssuance({
185
- chainId: uint32(block.chainid), count: uint104(70_000 * decimalMultiplier), beneficiary: multisig()
208
+ // forge-lint: disable-next-line(unsafe-typecast)
209
+ chainId: uint32(block.chainid),
210
+ // forge-lint: disable-next-line(unsafe-typecast)
211
+ count: uint104(70_000 * decimalMultiplier),
212
+ beneficiary: multisig()
186
213
  });
187
214
 
188
215
  stageConfigurations[0] = REVStageConfig({
@@ -190,6 +217,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
190
217
  autoIssuances: issuanceConfs,
191
218
  splitPercent: 2000,
192
219
  splits: splits,
220
+ // forge-lint: disable-next-line(unsafe-typecast)
193
221
  initialIssuance: uint112(1000 * decimalMultiplier),
194
222
  issuanceCutFrequency: 90 days,
195
223
  issuanceCutPercent: JBConstants.MAX_WEIGHT_CUT_PERCENT / 2,
@@ -198,9 +226,12 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
198
226
  });
199
227
 
200
228
  REVConfig memory revnetConfiguration = REVConfig({
201
- description: REVDescription(
202
- "Revnet", "$REV", "ipfs://QmNRHT91HcDgMcenebYX7rJigt77cgNcosvuhX21wkF3tx", ERC20_SALT
203
- ),
229
+ description: REVDescription({
230
+ name: "Revnet",
231
+ ticker: "$REV",
232
+ uri: "ipfs://QmNRHT91HcDgMcenebYX7rJigt77cgNcosvuhX21wkF3tx",
233
+ salt: ERC20_SALT
234
+ }),
204
235
  baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
205
236
  splitOperator: multisig(),
206
237
  stageConfigurations: stageConfigurations
@@ -237,7 +268,11 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
237
268
  REVStageConfig[] memory stageConfigurations = new REVStageConfig[](1);
238
269
  REVAutoIssuance[] memory issuanceConfs = new REVAutoIssuance[](1);
239
270
  issuanceConfs[0] = REVAutoIssuance({
240
- chainId: uint32(block.chainid), count: uint104(70_000 * decimalMultiplier), beneficiary: multisig()
271
+ // forge-lint: disable-next-line(unsafe-typecast)
272
+ chainId: uint32(block.chainid),
273
+ // forge-lint: disable-next-line(unsafe-typecast)
274
+ count: uint104(70_000 * decimalMultiplier),
275
+ beneficiary: multisig()
241
276
  });
242
277
 
243
278
  stageConfigurations[0] = REVStageConfig({
@@ -245,6 +280,7 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
245
280
  autoIssuances: issuanceConfs,
246
281
  splitPercent: 2000,
247
282
  splits: splits,
283
+ // forge-lint: disable-next-line(unsafe-typecast)
248
284
  initialIssuance: uint112(1000 * decimalMultiplier),
249
285
  issuanceCutFrequency: 90 days,
250
286
  issuanceCutPercent: JBConstants.MAX_WEIGHT_CUT_PERCENT / 2,
@@ -257,9 +293,12 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
257
293
  _loanSources[1] = REVLoanSource({token: address(TOKEN), terminal: jbMultiTerminal()});
258
294
 
259
295
  REVConfig memory revnetConfiguration = REVConfig({
260
- description: REVDescription(
261
- "NANA", "$NANA", "ipfs://QmNRHT91HcDgMcenebYX7rJigt77cgNxosvuhX21wkF3tx", "NANA_TOKEN"
262
- ),
296
+ description: REVDescription({
297
+ name: "NANA",
298
+ ticker: "$NANA",
299
+ uri: "ipfs://QmNRHT91HcDgMcenebYX7rJigt77cgNxosvuhX21wkF3tx",
300
+ salt: "NANA_TOKEN"
301
+ }),
263
302
  baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
264
303
  splitOperator: multisig(),
265
304
  stageConfigurations: stageConfigurations