@rev-net/core-v6 0.0.9 → 0.0.10

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 (46) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/README.md +4 -4
  3. package/SKILLS.md +2 -8
  4. package/STYLE_GUIDE.md +127 -51
  5. package/docs/src/README.md +2 -2
  6. package/foundry.toml +3 -0
  7. package/package.json +12 -9
  8. package/remappings.txt +1 -1
  9. package/script/Deploy.s.sol +1 -1
  10. package/script/helpers/RevnetCoreDeploymentLib.sol +1 -1
  11. package/src/REVDeployer.sol +30 -26
  12. package/src/REVLoans.sol +1 -0
  13. package/test/{REVDeployerAuditRegressions.t.sol → REVDeployerRegressions.t.sol} +1 -1
  14. package/test/REVInvincibility.t.sol +15 -19
  15. package/test/REVLifecycle.t.sol +0 -1
  16. package/test/REVLoansAttacks.t.sol +3 -7
  17. package/test/REVLoansFeeRecovery.t.sol +0 -2
  18. package/test/{REVLoans_AuditFindings.t.sol → REVLoansFindings.t.sol} +6 -6
  19. package/test/{REVLoansAuditRegressions.t.sol → REVLoansRegressions.t.sol} +2 -2
  20. package/test/REVLoansSourced.t.sol +3 -1
  21. package/test/{TestPR26_BurnHeldTokens.t.sol → TestBurnHeldTokens.t.sol} +1 -1
  22. package/test/{TestPR27_CEIPattern.t.sol → TestCEIPattern.t.sol} +3 -3
  23. package/test/{TestPR15_CashOutCallerValidation.t.sol → TestCashOutCallerValidation.t.sol} +1 -3
  24. package/test/{TestPR09_ConversionDocumentation.t.sol → TestConversionDocumentation.t.sol} +1 -1
  25. package/test/{TestPR13_CrossSourceReallocation.t.sol → TestCrossSourceReallocation.t.sol} +1 -1
  26. package/test/{TestPR12_FlashLoanSurplus.t.sol → TestFlashLoanSurplus.t.sol} +1 -1
  27. package/test/{TestPR22_HookArrayOOB.t.sol → TestHookArrayOOB.t.sol} +1 -1
  28. package/test/{TestPR10_LiquidationBehavior.t.sol → TestLiquidationBehavior.t.sol} +4 -4
  29. package/test/{TestPR11_LowFindings.t.sol → TestLowFindings.t.sol} +1 -1
  30. package/test/{TestPR32_MixedFixes.t.sol → TestMixedFixes.t.sol} +1 -1
  31. package/test/TestSplitWeightFork.t.sol +118 -159
  32. package/test/{TestPR29_SwapTerminalPermission.t.sol → TestSwapTerminalPermission.t.sol} +1 -1
  33. package/test/{TestPR21_Uint112Overflow.t.sol → TestUint112Overflow.t.sol} +4 -4
  34. package/test/{TestPR16_ZeroRepayment.t.sol → TestZeroRepayment.t.sol} +4 -6
  35. package/test/fork/ForkTestBase.sol +83 -51
  36. package/test/fork/TestCashOutFork.t.sol +12 -11
  37. package/test/fork/TestLoanBorrowFork.t.sol +10 -12
  38. package/test/fork/TestLoanCrossRulesetFork.t.sol +300 -0
  39. package/test/fork/TestLoanLiquidationFork.t.sol +13 -8
  40. package/test/fork/TestLoanReallocateFork.t.sol +21 -12
  41. package/test/fork/TestLoanRepayFork.t.sol +17 -14
  42. package/test/fork/TestSplitWeightFork.t.sol +34 -34
  43. package/test/mock/MockBuybackDataHook.sol +4 -7
  44. package/test/mock/MockBuybackDataHookMintPath.sol +5 -8
  45. package/test/regression/{TestI20_CumulativeLoanCounter.t.sol → TestCumulativeLoanCounter.t.sol} +4 -4
  46. package/test/regression/{TestL27_LiquidateGapHandling.t.sol → TestLiquidateGapHandling.t.sol} +3 -3
package/ARCHITECTURE.md CHANGED
@@ -26,7 +26,7 @@ Deployer → REVDeployer.deployFor()
26
26
  → Each stage: duration, weight, cashOutTaxRate, splits
27
27
  → Auto-issuance: pre-mint tokens to specified beneficiaries per chain
28
28
  → Set REVDeployer as data hook (controls pay + cashout behavior)
29
- Configure buyback hook (swap vs mint decision)
29
+ Initialize buyback pools at 1:1 price, configure buyback hook
30
30
  → Deploy suckers for cross-chain operation
31
31
  → Deploy 721 tiers if specified
32
32
  → Compute matching hash for cross-chain deployment verification
package/README.md CHANGED
@@ -16,9 +16,9 @@ Revnets are autonomous Juicebox projects with predetermined economic stages. Eac
16
16
 
17
17
  ```
18
18
  1. Deploy revnet with stage configurations
19
- → REVDeployer.deployFor(revnetId=0, config, terminals, ...)
19
+ → REVDeployer.deployFor(revnetId=0, config, terminals, suckerConfig)
20
20
  → Creates Juicebox project owned by REVDeployer (permanently)
21
- → Deploys ERC-20 token, configures buyback pools, deploys suckers
21
+ → Deploys ERC-20 token, initializes buyback pools at 1:1 price, deploys suckers
22
22
  |
23
23
  2. Stage 1 begins (startsAtOrAfter or block.timestamp)
24
24
  → Tokens issued at initialIssuance rate per unit of base currency
@@ -125,13 +125,13 @@ test/
125
125
  REVAutoIssuanceFuzz.t.sol # Auto-issuance fuzz tests
126
126
  REVInvincibility.t.sol # Economic property fuzzing
127
127
  REVInvincibilityHandler.sol # Fuzz handler
128
- REVDeployerAuditRegressions.t.sol # Deployer audit regressions
128
+ REVDeployerRegressions.t.sol # Deployer regressions
129
129
  REVLoansSourced.t.sol # Multi-source loan tests
130
130
  REVLoansUnSourced.t.sol # Loan error cases
131
131
  REVLoansFeeRecovery.t.sol # Fee calculation tests
132
132
  REVLoansAttacks.t.sol # Flash loan, reentrancy scenarios
133
133
  REVLoans.invariants.t.sol # Loan fuzzing invariants
134
- REVLoansAuditRegressions.t.sol # Loan audit regressions
134
+ REVLoansRegressions.t.sol # Loan regressions
135
135
  TestPR09-32_*.t.sol # Per-PR regression tests
136
136
  helpers/
137
137
  MaliciousContracts.sol # Attack contract mocks
package/SKILLS.md CHANGED
@@ -17,8 +17,8 @@ Deploy and manage Revnets -- autonomous, unowned Juicebox projects with staged i
17
17
 
18
18
  | Function | What it does |
19
19
  |----------|-------------|
20
- | `REVDeployer.deployFor(revnetId, config, terminals, buybackHookConfig, suckerConfig)` | Deploy a new revnet (`revnetId=0`) or convert an existing Juicebox project. Encodes stage configs into rulesets, deploys ERC-20 token, sets up split operator, buyback pools, suckers, and loans permissions. |
21
- | `REVDeployer.deployWith721sFor(revnetId, config, terminals, buybackHookConfig, suckerConfig, hookConfig, allowedPosts)` | Same as `deployFor` but also deploys a tiered ERC-721 hook. Optionally configures Croptop posting criteria and grants publisher permission to add tiers. |
20
+ | `REVDeployer.deployFor(revnetId, config, terminals, suckerConfig)` | Deploy a new revnet (`revnetId=0`) or convert an existing Juicebox project. Encodes stage configs into rulesets, deploys ERC-20 token, initializes buyback pool at 1:1 price, sets up split operator, suckers, and loans permissions. |
21
+ | `REVDeployer.deployWith721sFor(revnetId, config, terminals, suckerConfig, hookConfig, allowedPosts)` | Same as `deployFor` but also deploys a tiered ERC-721 hook. Optionally configures Croptop posting criteria and grants publisher permission to add tiers. |
22
22
  | `REVDeployer.deploySuckersFor(revnetId, suckerConfig)` | Deploy new cross-chain suckers post-launch. Split operator only. Validates ruleset allows sucker deployment (bit 2 of `extraMetadata`). Uses stored config hash for cross-chain matching. |
23
23
 
24
24
  ### Data Hooks
@@ -187,7 +187,6 @@ JBAccountingContext({
187
187
  import {REVConfig} from "@rev-net/core-v6/src/structs/REVConfig.sol";
188
188
  import {REVStageConfig} from "@rev-net/core-v6/src/structs/REVStageConfig.sol";
189
189
  import {REVDescription} from "@rev-net/core-v6/src/structs/REVDescription.sol";
190
- import {REVBuybackHookConfig} from "@rev-net/core-v6/src/structs/REVBuybackHookConfig.sol";
191
190
  import {REVSuckerDeploymentConfig} from "@rev-net/core-v6/src/structs/REVSuckerDeploymentConfig.sol";
192
191
  import {IREVDeployer} from "@rev-net/core-v6/src/interfaces/IREVDeployer.sol";
193
192
 
@@ -224,11 +223,6 @@ deployer.deployFor({
224
223
  revnetId: 0, // 0 = deploy new
225
224
  configuration: config,
226
225
  terminalConfigurations: terminals,
227
- buybackHookConfiguration: REVBuybackHookConfig({
228
- dataHook: IJBRulesetDataHook(address(0)),
229
- hookToConfigure: IJBBuybackHook(address(0)),
230
- poolConfigurations: new REVBuybackPoolConfig[](0)
231
- }),
232
226
  suckerDeploymentConfiguration: REVSuckerDeploymentConfig({
233
227
  deployerConfigurations: new JBSuckerDeployerConfig[](0),
234
228
  salt: bytes32(0)
package/STYLE_GUIDE.md CHANGED
@@ -17,8 +17,6 @@ src/
17
17
 
18
18
  One contract/interface/struct/enum per file. Name the file after the type it contains.
19
19
 
20
- **Structs, enums, libraries, and interfaces always go in their subdirectories** (`src/structs/`, `src/enums/`, `src/libraries/`, `src/interfaces/`) — never inline in contract files or placed in `src/` root. This keeps type definitions discoverable and import paths consistent across repos.
21
-
22
20
  ## Pragma Versions
23
21
 
24
22
  ```solidity
@@ -106,14 +104,6 @@ contract JBExample is JBPermissioned, IJBExample {
106
104
  // -------------------------- constructor ---------------------------- //
107
105
  //*********************************************************************//
108
106
 
109
- //*********************************************************************//
110
- // ---------------------- receive / fallback ------------------------- //
111
- //*********************************************************************//
112
-
113
- //*********************************************************************//
114
- // --------------------------- modifiers ----------------------------- //
115
- //*********************************************************************//
116
-
117
107
  //*********************************************************************//
118
108
  // ---------------------- external transactions ---------------------- //
119
109
  //*********************************************************************//
@@ -141,28 +131,23 @@ contract JBExample is JBPermissioned, IJBExample {
141
131
  ```
142
132
 
143
133
  **Section order:**
144
- 1. `using` declarations
145
- 2. Custom errors
146
- 3. Public constants
147
- 4. Internal constants
148
- 5. Public immutable stored properties
149
- 6. Internal immutable stored properties
150
- 7. Public stored properties
151
- 8. Internal stored properties
152
- 9. Constructor
153
- 10. `receive` / `fallback`
154
- 11. Modifiers
155
- 12. External transactions
156
- 13. External views
157
- 14. Public transactions
158
- 15. Internal helpers
159
- 16. Internal views
160
- 17. Private helpers
134
+ 1. Custom errors
135
+ 2. Public constants
136
+ 3. Internal constants
137
+ 4. Public immutable stored properties
138
+ 5. Internal immutable stored properties
139
+ 6. Public stored properties
140
+ 7. Internal stored properties
141
+ 8. Constructor
142
+ 9. External transactions
143
+ 10. External views
144
+ 11. Public transactions
145
+ 12. Internal helpers
146
+ 13. Internal views
147
+ 14. Private helpers
161
148
 
162
149
  Functions are alphabetized within each section.
163
150
 
164
- **Events:** Events are declared in interfaces only, never in implementation contracts. Implementations inherit events from their interface and emit them unqualified. This keeps the ABI definition in one place and allows tests to use interface-qualified event expectations (e.g., `emit IJBController.LaunchProject(...)`).
165
-
166
151
  ## Interface Structure
167
152
 
168
153
  ```solidity
@@ -334,9 +319,6 @@ optimizer_runs = 200
334
319
  libs = ["node_modules", "lib"]
335
320
  fs_permissions = [{ access = "read-write", path = "./"}]
336
321
 
337
- [profile.ci_sizes]
338
- optimizer_runs = 200
339
-
340
322
  [fuzz]
341
323
  runs = 4096
342
324
 
@@ -351,13 +333,13 @@ multiline_func_header = "all"
351
333
  wrap_comments = true
352
334
  ```
353
335
 
354
- **Variations:**
355
- - `evm_version = 'cancun'` for repos using transient storage (buyback-hook, router-terminal, univ4-router)
356
- - `via_ir = true` for repos hitting stack-too-deep (buyback-hook, banny-retail, univ4-lp-split-hook, deploy-all)
357
- - `optimizer = false` only for deploy-all-v6 (stack-too-deep with optimization)
358
- - `lint_on_build = false` for repos that depend on packages with test helpers using bare `src/` imports (solar linter can't resolve cross-package). Run `forge lint src/` explicitly.
336
+ **Optional sections (add only when needed):**
337
+ - `[rpc_endpoints]` repos with fork tests. Maps named endpoints to env vars (e.g. `ethereum = "${RPC_ETHEREUM_MAINNET}"`).
359
338
 
360
- > **This repo's deviations:** `optimizer_runs = 100` (stack-too-deep at 200 due to deep struct nesting), `via_ir = true`, `lint_on_build = false` (nana-core test helpers use bare `src/` imports that solar can't resolve cross-package). Package scope: `@rev-net/`.
339
+ **Common variations:**
340
+ - `via_ir = true` when hitting stack-too-deep
341
+ - `optimizer = false` when optimization causes stack-too-deep
342
+ - `optimizer_runs` reduced when deep struct nesting causes stack-too-deep at 200 runs
361
343
 
362
344
  ### CI Workflows
363
345
 
@@ -390,7 +372,7 @@ jobs:
390
372
  env:
391
373
  RPC_ETHEREUM_MAINNET: ${{ secrets.RPC_ETHEREUM_MAINNET }}
392
374
  - name: Check contract sizes
393
- run: FOUNDRY_PROFILE=ci_sizes forge build --sizes --skip "*/test/**" --skip "*/script/**" --skip SphinxUtils
375
+ run: forge build --sizes --skip "*/test/**" --skip "*/script/**" --skip SphinxUtils
394
376
  ```
395
377
 
396
378
  **lint.yml:**
@@ -412,6 +394,55 @@ jobs:
412
394
  run: forge fmt --check
413
395
  ```
414
396
 
397
+ **slither.yml** (repos with `src/` contracts only):
398
+ ```yaml
399
+ name: slither
400
+ on:
401
+ pull_request:
402
+ branches:
403
+ - main
404
+ push:
405
+ branches:
406
+ - main
407
+ jobs:
408
+ analyze:
409
+ runs-on: ubuntu-latest
410
+ steps:
411
+ - uses: actions/checkout@v4
412
+ with:
413
+ submodules: recursive
414
+ - uses: actions/setup-node@v4
415
+ with:
416
+ node-version: latest
417
+ - name: Install npm dependencies
418
+ run: npm install --omit=dev
419
+ - name: Install Foundry
420
+ uses: foundry-rs/foundry-toolchain@v1
421
+ - name: Run slither
422
+ uses: crytic/slither-action@v0.3.1
423
+ with:
424
+ slither-config: slither-ci.config.json
425
+ fail-on: medium
426
+ ```
427
+
428
+ **slither-ci.config.json:**
429
+ ```json
430
+ {
431
+ "detectors_to_exclude": "timestamp,uninitialized-local,naming-convention,solc-version,shadowing-local",
432
+ "exclude_informational": true,
433
+ "exclude_low": false,
434
+ "exclude_medium": false,
435
+ "exclude_high": false,
436
+ "disable_color": false,
437
+ "filter_paths": "(mocks/|test/|node_modules/|lib/)",
438
+ "legacy_ast": false
439
+ }
440
+ ```
441
+
442
+ **Variations:**
443
+ - Deployer-only repos (no `src/`, only `script/`) skip slither entirely — the action's internal `forge build` skips `test/` and `script/` by default, leaving nothing to compile.
444
+ - Use inline `// slither-disable-next-line <detector>` to suppress known false positives rather than adding to `detectors_to_exclude` in the config. The comment must be on the line immediately before the flagged expression.
445
+
415
446
  ### package.json
416
447
 
417
448
  ```json
@@ -436,13 +467,62 @@ jobs:
436
467
 
437
468
  ### remappings.txt
438
469
 
439
- Every repo has a `remappings.txt`. Minimal content:
470
+ Every repo has a `remappings.txt` as the **single source of truth** for import remappings. Never add remappings to `foundry.toml`.
471
+
472
+ **Principle:** Import paths in Solidity source must match npm package names exactly. With `libs = ["node_modules", "lib"]`, Foundry auto-resolves `@scope/package/path/File.sol` → `node_modules/@scope/package/path/File.sol`. No remapping needed for packages installed as real directories.
473
+
474
+ **Note:** Auto-resolution does **not** work for symlinked packages (e.g. npm workspace links). Workspace repos like `deploy-all-v6` and `nana-cli-v6` need explicit `@scope/package/=node_modules/@scope/package/` remappings for each symlinked dependency.
475
+
476
+ **Minimal content** (most repos):
477
+
478
+ ```
479
+ forge-std/=lib/forge-std/src/
480
+ ```
481
+
482
+ Only add extra remappings for:
483
+ - **`forge-std`** — always needed (git submodule with `src/` subdirectory)
484
+ - **Repo-specific `lib/` submodules** that have no npm package (e.g., `hookmate/=lib/hookmate/src/`)
485
+ - **Symlinked npm packages** — need explicit `@scope/package/=node_modules/@scope/package/` entries
486
+ - **Nested transitive deps** — e.g., `@chainlink/contracts-ccip/` nested inside `@bananapus/suckers-v6/node_modules/`
487
+
488
+ **Never add remappings for:**
489
+ - npm packages that match their import path and are installed as real directories — they auto-resolve
490
+ - Short-form aliases (e.g., `@bananapus/core/` → `@bananapus/core-v6/src/`) — fix the import instead
491
+ - Packages available via npm that are also git submodules — remove the submodule, use npm
492
+
493
+ **Import path convention:**
494
+
495
+ | Package | Import path | Resolves to |
496
+ |---------|------------|-------------|
497
+ | `@bananapus/core-v6` | `@bananapus/core-v6/src/libraries/JBConstants.sol` | `node_modules/@bananapus/core-v6/src/...` |
498
+ | `@openzeppelin/contracts` | `@openzeppelin/contracts/token/ERC20/IERC20.sol` | `node_modules/@openzeppelin/contracts/...` |
499
+ | `@uniswap/v4-core` | `@uniswap/v4-core/src/interfaces/IPoolManager.sol` | `node_modules/@uniswap/v4-core/src/...` |
440
500
 
501
+ ### Linting
502
+
503
+ Solar (Foundry's built-in linter) runs automatically during `forge build`. It scans all `.sol` files in `libs` directories, including `node_modules`.
504
+
505
+ **All test helpers must use relative imports** (e.g. `../../src/structs/JBRuleset.sol`), not bare `src/` imports. This ensures solar can resolve paths when the helper is consumed via npm in downstream repos.
506
+
507
+ ### Fork Tests
508
+
509
+ Fork tests use named RPC endpoints defined in `[rpc_endpoints]` of `foundry.toml`. No skip guards — fork tests should hard-fail if the RPC endpoint is unavailable, making CI failures explicit.
510
+
511
+ ```solidity
512
+ function setUp() public {
513
+ vm.createSelectFork("ethereum");
514
+ // ... setup code
515
+ }
441
516
  ```
442
- @sphinx-labs/contracts/=lib/sphinx/packages/contracts/contracts/foundry
517
+
518
+ The endpoint name (e.g. `"ethereum"`) maps to an env var via `foundry.toml`:
519
+
520
+ ```toml
521
+ [rpc_endpoints]
522
+ ethereum = "${RPC_ETHEREUM_MAINNET}"
443
523
  ```
444
524
 
445
- Additional mappings as needed for repo-specific dependencies.
525
+ For multi-chain fork tests, add all needed endpoints.
446
526
 
447
527
  ### Formatting
448
528
 
@@ -453,15 +533,6 @@ Run `forge fmt` before committing. The `[fmt]` config in `foundry.toml` enforces
453
533
 
454
534
  CI checks formatting via `forge fmt --check`.
455
535
 
456
- ### CI Secrets
457
-
458
- | Secret | Purpose |
459
- |--------|--------|
460
- | `NPM_TOKEN` | npm publish access (used by `publish.yml`) |
461
- | `RPC_ETHEREUM_MAINNET` | Ethereum mainnet RPC URL for fork tests (used by `test.yml`) |
462
-
463
- Fork tests require `RPC_ETHEREUM_MAINNET` — they fail if it's missing.
464
-
465
536
  ### Branching
466
537
 
467
538
  - `main` is the primary branch
@@ -480,3 +551,8 @@ Fork tests require `RPC_ETHEREUM_MAINNET` — they fail if it's missing.
480
551
  ### Contract Size Checks
481
552
 
482
553
  CI runs `forge build --sizes` to catch contracts approaching the 24KB limit.
554
+
555
+ ## Repo-Specific Deviations
556
+
557
+ - **`optimizer_runs = 100`** — reduced for contract size compliance
558
+ - **`npm install --omit=dev && npm install @sphinx-labs/contracts` in CI** — test files import deployment helpers from dependencies (`SuckerDeploymentLib`, `CroptopDeploymentLib`) that use `@sphinx-labs` contracts. Installing just the contracts package avoids the full `@sphinx-labs/plugins` tree (445+ Solidity files) that would bloat compilation
@@ -123,13 +123,13 @@ test/
123
123
  REVAutoIssuanceFuzz.t.sol # Auto-issuance fuzz tests
124
124
  REVInvincibility.t.sol # Economic property fuzzing
125
125
  REVInvincibilityHandler.sol # Fuzz handler
126
- REVDeployerAuditRegressions.t.sol # Deployer audit regressions
126
+ REVDeployerRegressions.t.sol # Deployer regressions
127
127
  REVLoansSourced.t.sol # Multi-source loan tests
128
128
  REVLoansUnSourced.t.sol # Loan error cases
129
129
  REVLoansFeeRecovery.t.sol # Fee calculation tests
130
130
  REVLoansAttacks.t.sol # Flash loan, reentrancy scenarios
131
131
  REVLoans.invariants.t.sol # Loan fuzzing invariants
132
- REVLoansAuditRegressions.t.sol # Loan audit regressions
132
+ REVLoansRegressions.t.sol # Loan regressions
133
133
  TestPR09-32_*.t.sol # Per-PR regression tests
134
134
  helpers/
135
135
  MaliciousContracts.sol # Attack contract mocks
package/foundry.toml CHANGED
@@ -17,6 +17,9 @@ fail_on_revert = false
17
17
  [lint]
18
18
  lint_on_build = false
19
19
 
20
+ [rpc_endpoints]
21
+ ethereum = "${RPC_ETHEREUM_MAINNET}"
22
+
20
23
  [fmt]
21
24
  number_underscore = "thousands"
22
25
  multiline_func_header = "all"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rev-net/core-v6",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,14 +20,17 @@
20
20
  "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'revnet-core-v6'"
21
21
  },
22
22
  "dependencies": {
23
- "@bananapus/721-hook-v6": "^0.0.13",
24
- "@bananapus/buyback-hook-v6": "^0.0.10",
25
- "@bananapus/core-v6": "^0.0.14",
26
- "@bananapus/permission-ids-v6": "^0.0.6",
27
- "@bananapus/router-terminal-v6": "^0.0.9",
28
- "@bananapus/suckers-v6": "^0.0.8",
29
- "@croptop/core-v6": "^0.0.10",
30
- "@openzeppelin/contracts": "^5.2.0"
23
+ "@bananapus/721-hook-v6": "^0.0.14",
24
+ "@bananapus/buyback-hook-v6": "^0.0.11",
25
+ "@bananapus/core-v6": "^0.0.15",
26
+ "@bananapus/ownable-v6": "^0.0.8",
27
+ "@bananapus/permission-ids-v6": "^0.0.7",
28
+ "@bananapus/router-terminal-v6": "^0.0.10",
29
+ "@bananapus/suckers-v6": "^0.0.9",
30
+ "@croptop/core-v6": "^0.0.14",
31
+ "@openzeppelin/contracts": "^5.6.1",
32
+ "@uniswap/v4-core": "^1.0.2",
33
+ "@uniswap/v4-periphery": "^1.0.3"
31
34
  },
32
35
  "devDependencies": {
33
36
  "@sphinx-labs/plugins": "^0.33.2"
package/remappings.txt CHANGED
@@ -1 +1 @@
1
- @sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry
1
+ forge-std/=lib/forge-std/src/
@@ -8,7 +8,7 @@ import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
8
8
  import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
9
9
  import "@croptop/core-v6/script/helpers/CroptopDeploymentLib.sol";
10
10
 
11
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
11
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
12
12
  import {Script} from "forge-std/Script.sol";
13
13
 
14
14
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
@@ -3,7 +3,7 @@ pragma solidity 0.8.26;
3
3
 
4
4
  import {stdJson} from "forge-std/Script.sol";
5
5
  import {Vm} from "forge-std/Vm.sol";
6
- import {SphinxConstants, NetworkInfo} from "@sphinx-labs/contracts/SphinxConstants.sol";
6
+ import {SphinxConstants, NetworkInfo} from "@sphinx-labs/contracts/contracts/foundry/SphinxConstants.sol";
7
7
 
8
8
  import {IREVDeployer} from "./../../src/interfaces/IREVDeployer.sol";
9
9
  import {IREVLoans} from "./../../src/interfaces/IREVLoans.sol";
@@ -99,8 +99,8 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
99
99
  uint24 public constant DEFAULT_BUYBACK_POOL_FEE = 10_000;
100
100
 
101
101
  /// @notice The default tick spacing used when auto-configuring buyback pools.
102
- /// @dev 60 is the standard tick spacing for the 1% fee tier.
103
- int24 public constant DEFAULT_BUYBACK_TICK_SPACING = 60;
102
+ /// @dev 200 aligns with UniV4DeploymentSplitHook.TICK_SPACING so both target the same pool.
103
+ int24 public constant DEFAULT_BUYBACK_TICK_SPACING = 200;
104
104
 
105
105
  /// @notice The default TWAP window used when auto-configuring buyback pools.
106
106
  /// @dev 2 days provides robust manipulation resistance.
@@ -326,6 +326,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
326
326
  bool usesTiered721Hook = address(tiered721Hook) != address(0);
327
327
  if (usesTiered721Hook) {
328
328
  JBPayHookSpecification[] memory specs;
329
+ // slither-disable-next-line unused-return
329
330
  (, specs) = IJBRulesetDataHook(address(tiered721Hook)).beforePayRecordedWith(context);
330
331
  // The 721 hook returns a single spec (itself) whose amount is the total split amount.
331
332
  if (specs.length > 0) {
@@ -441,17 +442,14 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
441
442
  return SUCKER_REGISTRY.isSuckerOf({projectId: revnetId, addr: addr});
442
443
  }
443
444
 
444
- /// @notice Initialize fund access limits for the loan contract and configure buyback pools for each terminal token.
445
+ /// @notice Initialize fund access limits for the loan contract.
445
446
  /// @dev Returns an unlimited surplus allowance for each terminal+token pair derived from the terminal
446
- /// configurations. Also auto-configures a buyback pool for each token with sensible defaults (1% fee, 2-day TWAP).
447
- /// @param revnetId The ID of the revnet to configure buyback pools for.
447
+ /// configurations.
448
448
  /// @param terminalConfigurations The terminals to set up for the revnet. Used for payments and cash outs.
449
449
  /// @return fundAccessLimitGroups The fund access limit groups for the loans.
450
- function _makeLoanFundAccessLimitsAndBuybackPools(
451
- uint256 revnetId,
452
- JBTerminalConfig[] calldata terminalConfigurations
453
- )
450
+ function _makeLoanFundAccessLimits(JBTerminalConfig[] calldata terminalConfigurations)
454
451
  internal
452
+ pure
455
453
  returns (JBFundAccessLimitGroup[] memory fundAccessLimitGroups)
456
454
  {
457
455
  // Count the total number of accounting contexts across all terminals.
@@ -463,7 +461,7 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
463
461
  // Initialize the fund access limit groups.
464
462
  fundAccessLimitGroups = new JBFundAccessLimitGroup[](count);
465
463
 
466
- // Set up the fund access limits and buyback pools.
464
+ // Set up the fund access limits.
467
465
  uint256 index;
468
466
  for (uint256 i; i < terminalConfigurations.length; i++) {
469
467
  JBTerminalConfig calldata terminalConfiguration = terminalConfigurations[i];
@@ -481,30 +479,28 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
481
479
  payoutLimits: new JBCurrencyAmount[](0),
482
480
  surplusAllowances: loanAllowances
483
481
  });
484
-
485
- // Configure a buyback pool for this terminal token with default fee and TWAP window.
486
- // slither-disable-next-line calls-loop
487
- _trySetBuybackPoolFor(revnetId, accountingContext.token);
488
482
  }
489
483
  }
490
484
  }
491
485
 
492
- /// @notice Try to configure a buyback pool for a terminal token. Silently catches failures (e.g., if the Uniswap V4
493
- /// pool isn't initialized yet).
486
+ /// @notice Try to initialize a Uniswap V4 buyback pool for a terminal token at a generic 1:1 price.
487
+ /// @dev Called after the ERC-20 token is deployed so the pool can be initialized in the PoolManager.
488
+ /// Silently catches failures (e.g., if the pool is already initialized).
494
489
  /// @param revnetId The ID of the revnet.
495
- /// @param terminalToken The terminal token to configure a buyback pool for.
496
- function _trySetBuybackPoolFor(uint256 revnetId, address terminalToken) internal {
497
- // Try to set the pool if the pool isn't initialized in the PoolManager yet, this will revert and be caught.
490
+ /// @param terminalToken The terminal token to initialize a buyback pool for.
491
+ function _tryInitializeBuybackPoolFor(uint256 revnetId, address terminalToken) internal {
492
+ // Try to initialize the pool at a generic 1:1 sqrtPriceX96 and configure the buyback hook.
498
493
  // The buyback hook constructs the PoolKey internally from the project token, terminal token, and pool params.
499
494
  // slither-disable-next-line calls-loop
500
- try BUYBACK_HOOK.setPoolFor({
495
+ try BUYBACK_HOOK.initializePoolFor({
501
496
  projectId: revnetId,
502
497
  fee: DEFAULT_BUYBACK_POOL_FEE,
503
498
  tickSpacing: DEFAULT_BUYBACK_TICK_SPACING,
504
499
  twapWindow: DEFAULT_BUYBACK_TWAP_WINDOW,
505
- terminalToken: terminalToken
500
+ terminalToken: terminalToken,
501
+ sqrtPriceX96: uint160(1 << 96)
506
502
  }) {}
507
- catch {} // Pool may not be initialized yet — that's OK.
503
+ catch {} // Pool may already be initialized — that's OK.
508
504
  }
509
505
 
510
506
  /// @notice Make a ruleset configuration for a revnet's stage.
@@ -1063,6 +1059,15 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
1063
1059
  salt: keccak256(abi.encode(configuration.description.salt, encodedConfigurationHash, _msgSender()))
1064
1060
  });
1065
1061
 
1062
+ // Now that the ERC-20 exists, initialize buyback pools for each terminal token.
1063
+ for (uint256 i; i < terminalConfigurations.length; i++) {
1064
+ JBTerminalConfig calldata terminalConfiguration = terminalConfigurations[i];
1065
+ for (uint256 j; j < terminalConfiguration.accountingContextsToAccept.length; j++) {
1066
+ // slither-disable-next-line calls-loop
1067
+ _tryInitializeBuybackPoolFor(revnetId, terminalConfiguration.accountingContextsToAccept[j].token);
1068
+ }
1069
+ }
1070
+
1066
1071
  // Give the split operator their permissions.
1067
1072
  _setSplitOperatorOf({revnetId: revnetId, operator: configuration.splitOperator});
1068
1073
 
@@ -1153,10 +1158,9 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
1153
1158
  configuration.description.salt
1154
1159
  );
1155
1160
 
1156
- // Initialize fund access limit groups for the loan contract and configure buyback pools.
1157
- JBFundAccessLimitGroup[] memory fundAccessLimitGroups = _makeLoanFundAccessLimitsAndBuybackPools({
1158
- revnetId: revnetId, terminalConfigurations: terminalConfigurations
1159
- });
1161
+ // Initialize fund access limit groups for the loan contract.
1162
+ JBFundAccessLimitGroup[] memory fundAccessLimitGroups =
1163
+ _makeLoanFundAccessLimits({terminalConfigurations: terminalConfigurations});
1160
1164
 
1161
1165
  // Iterate through each stage to set up its ruleset.
1162
1166
  for (uint256 i; i < configuration.stageConfigurations.length; i++) {
package/src/REVLoans.sol CHANGED
@@ -1206,6 +1206,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
1206
1206
  /// @param sourceFeeAmount The amount of the fee being taken from the revnet acting as the source of the loan.
1207
1207
  /// @param collateralCountToReturn The amount of collateral being returned that the loan no longer requires.
1208
1208
  /// @param beneficiary The address receiving the returned collateral and any tokens resulting from paying fees.
1209
+ // slither-disable-next-line reentrancy-eth,reentrancy-events
1209
1210
  function _repayLoan(
1210
1211
  uint256 loanId,
1211
1212
  REVLoan storage loan,
@@ -29,7 +29,7 @@ import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressReg
29
29
  import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
30
30
 
31
31
  /// @notice Regression tests for REVDeployer.
32
- contract REVDeployerRegressions_Local is TestBaseWorkflow {
32
+ contract REVDeployerRegressions is TestBaseWorkflow {
33
33
  using JBRulesetMetadataResolver for JBRuleset;
34
34
 
35
35
  bytes32 REV_DEPLOYER_SALT = "REVDeployer";