@bannynet/core-v6 0.0.6 → 0.0.7

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.
package/RISKS.md CHANGED
@@ -17,7 +17,7 @@ Deep implementation-level risk analysis of `Banny721TokenUriResolver`. All line
17
17
  - Severity: **CRITICAL** | Tested: **YES** (Fork.t.sol lines 931-956, BannyAttacks.t.sol)
18
18
  - When outfits or backgrounds are equipped via `decorateBannyWith()`, the NFT is transferred to the resolver contract via `safeTransferFrom` (lines 1191, 1325, 1366). The resolver holds custody until the body owner unequips.
19
19
  - **Impact**: If the resolver contract has a bug, equipped NFTs could become permanently locked. All value of equipped outfits depends on the resolver's correctness.
20
- - **Mitigation**: ReentrancyGuard on `decorateBannyWith` (line 977). `_tryTransferFrom` (lines 1375-1378) uses try-catch for returning old outfits, so burned/removed-tier tokens do not block redecoration. Tested in regression L62_BurnedTokenCheck.t.sol.
20
+ - **Mitigation**: ReentrancyGuard on `decorateBannyWith` (line 977). `_tryTransferFrom` (lines 1375-1378) uses try-catch for returning old outfits, so burned/removed-tier tokens do not block redecoration. Tested in regression BurnedTokenCheck.t.sol.
21
21
  - **Residual risk**: The resolver is not upgradeable. If a critical bug is found post-deployment, there is no admin mechanism to rescue stuck NFTs. The owner has no function to force-return assets.
22
22
 
23
23
  **Risk: Body transfer transfers outfit control**
@@ -47,7 +47,7 @@ Deep implementation-level risk analysis of `Banny721TokenUriResolver`. All line
47
47
  - Severity: **HIGH** | Tested: **YES** (Fork.t.sol lines 853-925)
48
48
  - `decorateBannyWith` calls `safeTransferFrom` (lines 1191, 1325, 1366) which triggers `onERC721Received` on receiving contracts. A malicious hook could attempt to re-enter `decorateBannyWith` during these callbacks.
49
49
  - **Mitigation**: `decorateBannyWith` has `nonReentrant` modifier (line 977, OpenZeppelin ReentrancyGuard). Tested with a purpose-built `ReentrantHook` (Fork.t.sol line 46) that re-enters during `safeTransferFrom`. The reentrancy attempt is caught and silently fails via try-catch.
50
- - **CEI pattern**: Background replacement follows Checks-Effects-Interactions. State updates (`_attachedBackgroundIdOf`, `_userOf`) happen at lines 1181-1182 before external transfers at lines 1186-1192. Verified in regression I25_CEIReorder.t.sol.
50
+ - **CEI pattern**: Background replacement follows Checks-Effects-Interactions. State updates (`_attachedBackgroundIdOf`, `_userOf`) happen at lines 1181-1182 before external transfers at lines 1186-1192. Verified in regression CEIReorder.t.sol.
51
51
  - **Residual risk**: None identified. The ReentrancyGuard provides a hard block, and CEI ordering provides defense-in-depth.
52
52
 
53
53
  ### MEDIUM -- Hook Trust Boundary
@@ -60,7 +60,7 @@ Deep implementation-level risk analysis of `Banny721TokenUriResolver`. All line
60
60
  - **Residual risk**: If a user interacts with a malicious hook, they could lose the NFTs they equip on that hook. The resolver cannot distinguish legitimate from malicious hooks.
61
61
 
62
62
  **Risk: Removed tier desynchronization**
63
- - Severity: **MEDIUM** | Tested: **YES** (M8_RemovedTierDesync.t.sol, 6 test cases)
63
+ - Severity: **MEDIUM** | Tested: **YES** (RemovedTierDesync.t.sol, 6 test cases)
64
64
  - When a tier is removed from the JB721TiersHookStore, `_productOfTokenId()` returns a zeroed struct (category=0, id=0). Previously equipped outfits from that tier have category 0 in the redecoration loop.
65
65
  - **Impact**: Without proper handling, removed-tier outfits could cause the `_decorateBannyWithOutfits` loop to malfunction -- the category-0 entries would be processed incorrectly by the `while` loop (line 1297).
66
66
  - **Mitigation**: The current code handles this correctly. Category-0 entries are processed and transferred out by the while loop. The `_tryTransferFrom` (line 1303, 1345) silently handles cases where the token no longer exists. Six regression tests verify: first/middle/last tier removal, all tiers removed, replacement after removal, and two consecutive removed tiers.
@@ -133,13 +133,13 @@ Deep implementation-level risk analysis of `Banny721TokenUriResolver`. All line
133
133
  | `DecorateFlow.t.sol` | ~40 | L18 vulnerability proof, multi-body outfit reuse, authorization flows, three-party interactions, background replacement, edge cases |
134
134
  | `BannyAttacks.t.sol` | 8 | Adversarial: outfit reuse, lock bypass, category conflicts, unauthorized decoration, out-of-order categories, body/background as outfit |
135
135
  | `Fork.t.sol` | 40+ | E2E against real JB infrastructure: full lifecycle, multi-actor, reentrancy (ReentrantHook), griefing/front-running, cross-hook isolation, redressing cycles |
136
- | `regression/I25_CEIReorder.t.sol` | 3 | CEI ordering in background replacement |
137
- | `regression/M8_RemovedTierDesync.t.sol` | 6 | Removed tier handling during redecoration |
138
- | `regression/L58_ArrayLengthValidation.t.sol` | 3 | Array length mismatch reverts |
139
- | `regression/L57_BodyCategoryValidation.t.sol` | 2 | Non-body token as bannyBodyId rejection |
140
- | `regression/L56_MsgSenderEvents.t.sol` | 4 | Events emit `_msgSender()` not `msg.sender` |
141
- | `regression/L62_BurnedTokenCheck.t.sol` | 2 | Burned equipped tokens do not lock the body |
142
- | `regression/L59_ClearMetadata.t.sol` | 2 | setMetadata can clear fields to empty strings |
136
+ | `regression/CEIReorder.t.sol` | 3 | CEI ordering in background replacement |
137
+ | `regression/RemovedTierDesync.t.sol` | 6 | Removed tier handling during redecoration |
138
+ | `regression/ArrayLengthValidation.t.sol` | 3 | Array length mismatch reverts |
139
+ | `regression/BodyCategoryValidation.t.sol` | 2 | Non-body token as bannyBodyId rejection |
140
+ | `regression/MsgSenderEvents.t.sol` | 4 | Events emit `_msgSender()` not `msg.sender` |
141
+ | `regression/BurnedTokenCheck.t.sol` | 2 | Burned equipped tokens do not lock the body |
142
+ | `regression/ClearMetadata.t.sol` | 2 | setMetadata can clear fields to empty strings |
143
143
 
144
144
  ## Untested Areas
145
145
 
package/STYLE_GUIDE.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  How we write Solidity and organize repos across the Juicebox V6 ecosystem. `nana-core-v6` is the gold standard — when in doubt, match what it does.
4
4
 
5
- **This repo's deviations:** `via_ir = true` (stack depth). Package scope: `@bannynet/`.
6
-
7
5
  ## File Organization
8
6
 
9
7
  ```
@@ -19,8 +17,6 @@ src/
19
17
 
20
18
  One contract/interface/struct/enum per file. Name the file after the type it contains.
21
19
 
22
- **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.
23
-
24
20
  ## Pragma Versions
25
21
 
26
22
  ```solidity
@@ -108,14 +104,6 @@ contract JBExample is JBPermissioned, IJBExample {
108
104
  // -------------------------- constructor ---------------------------- //
109
105
  //*********************************************************************//
110
106
 
111
- //*********************************************************************//
112
- // ---------------------- receive / fallback ------------------------- //
113
- //*********************************************************************//
114
-
115
- //*********************************************************************//
116
- // --------------------------- modifiers ----------------------------- //
117
- //*********************************************************************//
118
-
119
107
  //*********************************************************************//
120
108
  // ---------------------- external transactions ---------------------- //
121
109
  //*********************************************************************//
@@ -143,28 +131,23 @@ contract JBExample is JBPermissioned, IJBExample {
143
131
  ```
144
132
 
145
133
  **Section order:**
146
- 1. `using` declarations
147
- 2. Custom errors
148
- 3. Public constants
149
- 4. Internal constants
150
- 5. Public immutable stored properties
151
- 6. Internal immutable stored properties
152
- 7. Public stored properties
153
- 8. Internal stored properties
154
- 9. Constructor
155
- 10. `receive` / `fallback`
156
- 11. Modifiers
157
- 12. External transactions
158
- 13. External views
159
- 14. Public transactions
160
- 15. Internal helpers
161
- 16. Internal views
162
- 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
163
148
 
164
149
  Functions are alphabetized within each section.
165
150
 
166
- **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(...)`).
167
-
168
151
  ## Interface Structure
169
152
 
170
153
  ```solidity
@@ -333,13 +316,9 @@ Standard config across all repos:
333
316
  solc = '0.8.26'
334
317
  evm_version = 'cancun'
335
318
  optimizer_runs = 200
336
- via_ir = true
337
319
  libs = ["node_modules", "lib"]
338
320
  fs_permissions = [{ access = "read-write", path = "./"}]
339
321
 
340
- [profile.ci_sizes]
341
- optimizer_runs = 200
342
-
343
322
  [fuzz]
344
323
  runs = 4096
345
324
 
@@ -354,10 +333,14 @@ multiline_func_header = "all"
354
333
  wrap_comments = true
355
334
  ```
356
335
 
357
- **Variations:**
358
- - `evm_version = 'cancun'` for repos using transient storage (buyback-hook, router-terminal, univ4-router)
359
- - `via_ir = true` for repos hitting stack-too-deep (buyback-hook, banny-retail, univ4-lp-split-hook, deploy-all)
360
- - `optimizer = false` only for deploy-all-v6 (stack-too-deep with optimization)
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}"`).
338
+ - `[profile.ci_sizes]` only when CI needs different optimizer settings than defaults for the size check step (e.g. `optimizer_runs = 200` when the default profile uses a lower value).
339
+
340
+ **Common variations:**
341
+ - `via_ir = true` when hitting stack-too-deep
342
+ - `optimizer = false` when optimization causes stack-too-deep
343
+ - `optimizer_runs` reduced when deep struct nesting causes stack-too-deep at 200 runs
361
344
 
362
345
  ### CI Workflows
363
346
 
@@ -390,7 +373,7 @@ jobs:
390
373
  env:
391
374
  RPC_ETHEREUM_MAINNET: ${{ secrets.RPC_ETHEREUM_MAINNET }}
392
375
  - name: Check contract sizes
393
- run: FOUNDRY_PROFILE=ci_sizes forge build --sizes --skip "*/test/**" --skip "*/script/**" --skip SphinxUtils
376
+ run: forge build --sizes --skip "*/test/**" --skip "*/script/**" --skip SphinxUtils
394
377
  ```
395
378
 
396
379
  **lint.yml:**
@@ -412,11 +395,60 @@ jobs:
412
395
  run: forge fmt --check
413
396
  ```
414
397
 
398
+ **slither.yml** (repos with `src/` contracts only):
399
+ ```yaml
400
+ name: slither
401
+ on:
402
+ pull_request:
403
+ branches:
404
+ - main
405
+ push:
406
+ branches:
407
+ - main
408
+ jobs:
409
+ analyze:
410
+ runs-on: ubuntu-latest
411
+ steps:
412
+ - uses: actions/checkout@v4
413
+ with:
414
+ submodules: recursive
415
+ - uses: actions/setup-node@v4
416
+ with:
417
+ node-version: latest
418
+ - name: Install npm dependencies
419
+ run: npm install --omit=dev
420
+ - name: Install Foundry
421
+ uses: foundry-rs/foundry-toolchain@v1
422
+ - name: Run slither
423
+ uses: crytic/slither-action@v0.3.1
424
+ with:
425
+ slither-config: slither-ci.config.json
426
+ fail-on: medium
427
+ ```
428
+
429
+ **slither-ci.config.json:**
430
+ ```json
431
+ {
432
+ "detectors_to_exclude": "timestamp,uninitialized-local,naming-convention,solc-version,shadowing-local",
433
+ "exclude_informational": true,
434
+ "exclude_low": false,
435
+ "exclude_medium": false,
436
+ "exclude_high": false,
437
+ "disable_color": false,
438
+ "filter_paths": "(mocks/|test/|node_modules/|lib/)",
439
+ "legacy_ast": false
440
+ }
441
+ ```
442
+
443
+ **Variations:**
444
+ - 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.
445
+ - 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.
446
+
415
447
  ### package.json
416
448
 
417
449
  ```json
418
450
  {
419
- "name": "@bannynet/core-v6",
451
+ "name": "@bananapus/package-name-v6",
420
452
  "version": "x.x.x",
421
453
  "license": "MIT",
422
454
  "repository": { "type": "git", "url": "git+https://github.com/Org/repo.git" },
@@ -436,13 +468,62 @@ jobs:
436
468
 
437
469
  ### remappings.txt
438
470
 
439
- Every repo has a `remappings.txt`. Minimal content:
471
+ Every repo has a `remappings.txt` as the **single source of truth** for import remappings. Never add remappings to `foundry.toml`.
472
+
473
+ **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.
474
+
475
+ **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.
476
+
477
+ **Minimal content** (most repos):
440
478
 
441
479
  ```
442
- @sphinx-labs/contracts/=lib/sphinx/packages/contracts/contracts/foundry
480
+ forge-std/=lib/forge-std/src/
443
481
  ```
444
482
 
445
- Additional mappings as needed for repo-specific dependencies.
483
+ Only add extra remappings for:
484
+ - **`forge-std`** — always needed (git submodule with `src/` subdirectory)
485
+ - **Repo-specific `lib/` submodules** that have no npm package (e.g., `hookmate/=lib/hookmate/src/`)
486
+ - **Symlinked npm packages** — need explicit `@scope/package/=node_modules/@scope/package/` entries
487
+ - **Nested transitive deps** — e.g., `@chainlink/contracts-ccip/` nested inside `@bananapus/suckers-v6/node_modules/`
488
+
489
+ **Never add remappings for:**
490
+ - npm packages that match their import path and are installed as real directories — they auto-resolve
491
+ - Short-form aliases (e.g., `@bananapus/core/` → `@bananapus/core-v6/src/`) — fix the import instead
492
+ - Packages available via npm that are also git submodules — remove the submodule, use npm
493
+
494
+ **Import path convention:**
495
+
496
+ | Package | Import path | Resolves to |
497
+ |---------|------------|-------------|
498
+ | `@bananapus/core-v6` | `@bananapus/core-v6/src/libraries/JBConstants.sol` | `node_modules/@bananapus/core-v6/src/...` |
499
+ | `@openzeppelin/contracts` | `@openzeppelin/contracts/token/ERC20/IERC20.sol` | `node_modules/@openzeppelin/contracts/...` |
500
+ | `@uniswap/v4-core` | `@uniswap/v4-core/src/interfaces/IPoolManager.sol` | `node_modules/@uniswap/v4-core/src/...` |
501
+
502
+ ### Linting
503
+
504
+ Solar (Foundry's built-in linter) runs automatically during `forge build`. It scans all `.sol` files in `libs` directories, including `node_modules`.
505
+
506
+ **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.
507
+
508
+ ### Fork Tests
509
+
510
+ 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.
511
+
512
+ ```solidity
513
+ function setUp() public {
514
+ vm.createSelectFork("ethereum");
515
+ // ... setup code
516
+ }
517
+ ```
518
+
519
+ The endpoint name (e.g. `"ethereum"`) maps to an env var via `foundry.toml`:
520
+
521
+ ```toml
522
+ [rpc_endpoints]
523
+ ethereum = "${RPC_ETHEREUM_MAINNET}"
524
+ ```
525
+
526
+ For multi-chain fork tests, add all needed endpoints.
446
527
 
447
528
  ### Formatting
448
529
 
@@ -453,15 +534,6 @@ Run `forge fmt` before committing. The `[fmt]` config in `foundry.toml` enforces
453
534
 
454
535
  CI checks formatting via `forge fmt --check`.
455
536
 
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
537
  ### Branching
466
538
 
467
539
  - `main` is the primary branch
@@ -479,4 +551,8 @@ Fork tests require `RPC_ETHEREUM_MAINNET` — they fail if it's missing.
479
551
 
480
552
  ### Contract Size Checks
481
553
 
482
- CI runs `FOUNDRY_PROFILE=ci_sizes forge build --sizes` to catch contracts approaching the 24KB limit. The `ci_sizes` profile uses `optimizer_runs = 200` for realistic size measurement even when the default profile has different optimizer settings.
554
+ CI runs `forge build --sizes` to catch contracts approaching the 24KB limit. When the repo's default `optimizer_runs` differs from what you want for size checking, use `FOUNDRY_PROFILE=ci_sizes forge build --sizes` with a `[profile.ci_sizes]` section in `foundry.toml`.
555
+
556
+ ## Repo-Specific Deviations
557
+
558
+ None. This repo follows the standard configuration exactly.
package/foundry.toml CHANGED
@@ -6,9 +6,6 @@ via_ir = true
6
6
  libs = ["node_modules", "lib"]
7
7
  fs_permissions = [{ access = "read-write", path = "./"}]
8
8
 
9
- [profile.ci_sizes]
10
- optimizer_runs = 200
11
-
12
9
  [fuzz]
13
10
  runs = 4096
14
11
 
@@ -21,3 +18,6 @@ fail_on_revert = false
21
18
  number_underscore = "thousands"
22
19
  multiline_func_header = "all"
23
20
  wrap_comments = true
21
+
22
+ [rpc_endpoints]
23
+ ethereum = "${RPC_ETHEREUM_MAINNET}"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bannynet/core-v6",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,15 +20,17 @@
20
20
  "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'banny-core-v6'"
21
21
  },
22
22
  "dependencies": {
23
- "@bananapus/721-hook-v6": "^0.0.9",
24
- "@bananapus/core-v6": "^0.0.10",
23
+ "@bananapus/721-hook-v6": "^0.0.14",
24
+ "@bananapus/core-v6": "^0.0.15",
25
+ "@bananapus/permission-ids-v6": "^0.0.7",
25
26
  "@bananapus/router-terminal-v6": "^0.0.6",
26
27
  "@bananapus/suckers-v6": "^0.0.7",
27
- "@openzeppelin/contracts": "5.2.0",
28
- "@rev-net/core-v6": "^0.0.6",
28
+ "@croptop/core-v6": "^0.0.12",
29
+ "@openzeppelin/contracts": "^5.6.1",
30
+ "@rev-net/core-v6": "^0.0.10",
29
31
  "keccak": "^3.0.4"
30
32
  },
31
33
  "devDependencies": {
32
34
  "@sphinx-labs/plugins": "^0.33.2"
33
35
  }
34
- }
36
+ }
package/remappings.txt CHANGED
@@ -1 +1 @@
1
- @sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry
1
+ forge-std/=lib/forge-std/src/
@@ -9,7 +9,7 @@ import "./helpers/BannyverseDeploymentLib.sol";
9
9
  import "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
10
10
  import "@openzeppelin/contracts/utils/Strings.sol";
11
11
 
12
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
12
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
13
13
  import {Script} from "forge-std/Script.sol";
14
14
 
15
15
  contract Drop1Script is Script, Sphinx {
@@ -10,8 +10,8 @@ import "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
10
10
  import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
11
11
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
12
12
  import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
13
- import {JB721TiersHookFlags} from "@bananapus/721-hook-v6/src/structs/JB721TiersHookFlags.sol";
14
- import {JBDeploy721TiersHookConfig} from "@bananapus/721-hook-v6/src/structs/JBDeploy721TiersHookConfig.sol";
13
+ import {REVBaseline721HookConfig} from "@rev-net/core-v6/src/structs/REVBaseline721HookConfig.sol";
14
+ import {REV721TiersHookFlags} from "@rev-net/core-v6/src/structs/REV721TiersHookFlags.sol";
15
15
  import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
16
16
  import {IJBSplitHook} from "@bananapus/core-v6/src/interfaces/IJBSplitHook.sol";
17
17
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
@@ -30,7 +30,7 @@ import {REVSuckerDeploymentConfig} from "@rev-net/core-v6/src/structs/REVSuckerD
30
30
  import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
31
31
  import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
32
32
 
33
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
33
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
34
34
  import {Script} from "forge-std/Script.sol";
35
35
 
36
36
  import {Banny721TokenUriResolver} from "./../src/Banny721TokenUriResolver.sol";
@@ -331,7 +331,7 @@ contract DeployScript is Script, Sphinx {
331
331
  terminalConfigurations: terminalConfigurations,
332
332
  suckerDeploymentConfiguration: suckerDeploymentConfiguration,
333
333
  hookConfiguration: REVDeploy721TiersHookConfig({
334
- baseline721HookConfiguration: JBDeploy721TiersHookConfig({
334
+ baseline721HookConfiguration: REVBaseline721HookConfig({
335
335
  name: "Banny Retail",
336
336
  symbol: "BANNY",
337
337
  baseUri: BASE_URI,
@@ -342,12 +342,11 @@ contract DeployScript is Script, Sphinx {
342
342
  tiers: tiers, currency: ETH_CURRENCY, decimals: DECIMALS, prices: core.prices
343
343
  }),
344
344
  reserveBeneficiary: address(0),
345
- flags: JB721TiersHookFlags({
345
+ flags: REV721TiersHookFlags({
346
346
  noNewTiersWithReserves: false,
347
347
  noNewTiersWithVotes: false,
348
348
  noNewTiersWithOwnerMinting: false,
349
- preventOverspending: false,
350
- issueTokensForSplits: false
349
+ preventOverspending: false
351
350
  })
352
351
  }),
353
352
  salt: HOOK_SALT,
@@ -9,7 +9,7 @@ import "./helpers/BannyverseDeploymentLib.sol";
9
9
  import "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
10
10
  import "@openzeppelin/contracts/utils/Strings.sol";
11
11
 
12
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
12
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
13
13
  import {Script} from "forge-std/Script.sol";
14
14
 
15
15
  contract Drop1Script is Script, Sphinx {
@@ -6,7 +6,7 @@ import {Vm} from "forge-std/Vm.sol";
6
6
 
7
7
  import {Banny721TokenUriResolver} from "../../src/Banny721TokenUriResolver.sol";
8
8
 
9
- import {SphinxConstants, NetworkInfo} from "@sphinx-labs/contracts/SphinxConstants.sol";
9
+ import {SphinxConstants, NetworkInfo} from "@sphinx-labs/contracts/contracts/foundry/SphinxConstants.sol";
10
10
 
11
11
  struct BannyverseDeployment {
12
12
  uint256 revnetId;
@@ -1029,7 +1029,7 @@ import {Script} from "forge-std/Script.sol";
1029
1029
  import {console} from "forge-std/console.sol";
1030
1030
  ${imports}
1031
1031
  import {JB721TiersHook} from "@bananapus/721-hook-v5/src/JB721TiersHook.sol";
1032
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
1032
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
1033
1033
  import {IJBTerminal} from "@bananapus/core-v5/src/interfaces/IJBTerminal.sol";
1034
1034
  import {JBConstants} from "@bananapus/core-v5/src/libraries/JBConstants.sol";
1035
1035
  import {JBMetadataResolver} from "@bananapus/core-v5/src/libraries/JBMetadataResolver.sol";
@@ -1596,7 +1596,7 @@ import {MigrationContractArbitrum3} from "./MigrationContractArbitrum3.sol";
1596
1596
  import {MigrationContractArbitrum4} from "./MigrationContractArbitrum4.sol";
1597
1597
 
1598
1598
  import {JB721TiersHook} from "@bananapus/721-hook-v5/src/JB721TiersHook.sol";
1599
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
1599
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
1600
1600
  import {IJBTerminal} from "@bananapus/core-v5/src/interfaces/IJBTerminal.sol";
1601
1601
  import {JBConstants} from "@bananapus/core-v5/src/libraries/JBConstants.sol";
1602
1602
  import {JBMetadataResolver} from "@bananapus/core-v5/src/libraries/JBMetadataResolver.sol";
@@ -1,10 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
5
- import {IERC721} from "@bananapus/721-hook-v6/src/abstract/ERC721.sol";
6
- import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
7
- import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
4
+ import {Test} from "forge-std/Test.sol";
8
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
9
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
10
7
 
@@ -1,10 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
5
- import {IERC721} from "@bananapus/721-hook-v6/src/abstract/ERC721.sol";
6
- import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
7
- import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
4
+ import {Test} from "forge-std/Test.sol";
8
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
9
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
10
7
 
@@ -1,10 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
5
- import {IERC721} from "@bananapus/721-hook-v6/src/abstract/ERC721.sol";
6
- import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
7
- import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
4
+ import {Test} from "forge-std/Test.sol";
8
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
9
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
10
7
 
package/test/Fork.t.sol CHANGED
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
4
+ import {Test} from "forge-std/Test.sol";
5
5
 
6
6
  // JB core — deploy fresh within fork.
7
7
  import {JBPermissions} from "@bananapus/core-v6/src/JBPermissions.sol";
@@ -14,7 +14,6 @@ import {JBSplits} from "@bananapus/core-v6/src/JBSplits.sol";
14
14
  import {JBPrices} from "@bananapus/core-v6/src/JBPrices.sol";
15
15
  import {JBController} from "@bananapus/core-v6/src/JBController.sol";
16
16
  import {JBFundAccessLimits} from "@bananapus/core-v6/src/JBFundAccessLimits.sol";
17
- import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
18
17
 
19
18
  // 721 hook — deploy fresh within fork.
20
19
  import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
@@ -22,7 +21,6 @@ import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
22
21
  import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
23
22
  import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
24
23
  import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
25
- import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
26
24
  import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
27
25
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
28
26
  import {JB721TiersHookFlags} from "@bananapus/721-hook-v6/src/structs/JB721TiersHookFlags.sol";
@@ -39,7 +37,6 @@ import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Recei
39
37
 
40
38
  // Banny.
41
39
  import {Banny721TokenUriResolver} from "../src/Banny721TokenUriResolver.sol";
42
- import {IBanny721TokenUriResolver} from "../src/interfaces/IBanny721TokenUriResolver.sol";
43
40
 
44
41
  /// @notice Malicious hook for reentrancy testing. Re-enters the resolver during safeTransferFrom.
45
42
  contract ReentrantHook {
@@ -235,13 +232,7 @@ contract BannyForkTest is Test {
235
232
  // ──────────────────────────────────────
236
233
 
237
234
  function setUp() public {
238
- // Skip fork tests when no RPC URL is configured.
239
- string memory rpcUrl = vm.envOr("RPC_ETHEREUM_MAINNET", string(""));
240
- if (bytes(rpcUrl).length == 0) {
241
- vm.skip(true);
242
- return;
243
- }
244
- vm.createSelectFork(rpcUrl);
235
+ vm.createSelectFork("ethereum");
245
236
 
246
237
  // Clear any mainnet code at actor addresses (makeAddr may collide with deployed contracts).
247
238
  vm.etch(alice, "");
@@ -1832,7 +1823,8 @@ contract BannyForkTest is Test {
1832
1823
  JB721TiersHookStore store = new JB721TiersHookStore();
1833
1824
  JBAddressRegistry addressRegistry = new JBAddressRegistry();
1834
1825
 
1835
- JB721TiersHook hookImpl = new JB721TiersHook(jbDirectory, jbPermissions, jbRulesets, store, trustedForwarder);
1826
+ JB721TiersHook hookImpl =
1827
+ new JB721TiersHook(jbDirectory, jbPermissions, jbRulesets, store, jbSplits, trustedForwarder);
1836
1828
 
1837
1829
  hookDeployer = new JB721TiersHookDeployer(hookImpl, store, addressRegistry, trustedForwarder);
1838
1830
  }
@@ -1,13 +1,12 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
5
- import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
4
+ import {Test} from "forge-std/Test.sol";
6
5
 
7
6
  import {Banny721TokenUriResolver} from "../../src/Banny721TokenUriResolver.sol";
8
7
 
9
8
  /// @notice Mismatched array lengths should revert.
10
- contract L58_ArrayLengthValidationTest is Test {
9
+ contract ArrayLengthValidationTest is Test {
11
10
  Banny721TokenUriResolver resolver;
12
11
  address deployer = makeAddr("deployer");
13
12
 
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
4
+ import {Test} from "forge-std/Test.sol";
5
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
6
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
7
7
 
@@ -68,7 +68,7 @@ contract MockStore57 {
68
68
  }
69
69
 
70
70
  /// @notice decorateBannyWith should reject non-body-category tokens as bannyBodyId.
71
- contract L57_BodyCategoryValidationTest is Test {
71
+ contract BodyCategoryValidationTest is Test {
72
72
  Banny721TokenUriResolver resolver;
73
73
  MockHook57 hook;
74
74
  MockStore57 store;
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
4
+ import {Test} from "forge-std/Test.sol";
5
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
6
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
7
7
 
@@ -79,7 +79,7 @@ contract MockStore62 {
79
79
  }
80
80
 
81
81
  /// @notice Burned equipped tokens should not lock the body.
82
- contract L62_BurnedTokenCheckTest is Test {
82
+ contract BurnedTokenCheckTest is Test {
83
83
  Banny721TokenUriResolver resolver;
84
84
  MockHook62 hook;
85
85
  MockStore62 store;
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
4
+ import {Test} from "forge-std/Test.sol";
5
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
6
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
7
7
 
@@ -79,7 +79,7 @@ contract MockStoreI25 {
79
79
  /// @dev The fix reordered state writes (effects) before external transfers (interactions)
80
80
  /// in _decorateBannyWithBackground. This test verifies that after a background replacement,
81
81
  /// state is consistent and both the old background return and new background custody work.
82
- contract I25_CEIReorderTest is Test {
82
+ contract CEIReorderTest is Test {
83
83
  Banny721TokenUriResolver resolver;
84
84
  MockHookI25 hook;
85
85
  MockStoreI25 store;
@@ -1,12 +1,12 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
4
+ import {Test} from "forge-std/Test.sol";
5
5
 
6
6
  import {Banny721TokenUriResolver} from "../../src/Banny721TokenUriResolver.sol";
7
7
 
8
8
  /// @notice setMetadata should allow clearing fields to empty string.
9
- contract L59_ClearMetadataTest is Test {
9
+ contract ClearMetadataTest is Test {
10
10
  Banny721TokenUriResolver resolver;
11
11
  address deployer = makeAddr("deployer");
12
12
 
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
4
+ import {Test} from "forge-std/Test.sol";
5
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
6
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
7
7
 
@@ -69,7 +69,7 @@ contract MockStore56 {
69
69
  }
70
70
 
71
71
  /// @notice Events should emit _msgSender(), not msg.sender.
72
- contract L56_MsgSenderEventsTest is Test {
72
+ contract MsgSenderEventsTest is Test {
73
73
  Banny721TokenUriResolver resolver;
74
74
  MockHook56 hook;
75
75
  MockStore56 store;
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "forge-std/Test.sol";
4
+ import {Test} from "forge-std/Test.sol";
5
5
  import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
6
6
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
7
7
 
@@ -86,7 +86,7 @@ contract MockStoreM8 {
86
86
  /// @dev When a previously equipped outfit's tier is removed, `_productOfTokenId` returns category 0.
87
87
  /// Before the fix, this caused the first while loop to exit immediately (due to `!= 0` guard),
88
88
  /// and the second while loop would transfer out outfits that were being re-equipped.
89
- contract M8_RemovedTierDesyncTest is Test {
89
+ contract RemovedTierDesyncTest is Test {
90
90
  Banny721TokenUriResolver resolver;
91
91
  MockHookM8 hook;
92
92
  MockStoreM8 store;