@bannynet/core-v6 0.0.6 → 0.0.8

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
@@ -214,7 +197,7 @@ interface IJBExample is IJBBase {
214
197
  | Public/external function | `camelCase` | `cashOutTokensOf` |
215
198
  | Internal/private function | `_camelCase` | `_processFee` |
216
199
  | Internal storage | `_camelCase` | `_accountingContextForTokenOf` |
217
- | Function parameter | `camelCase` | `projectId`, `cashOutCount` |
200
+ | Function parameter | `camelCase` (no underscores) | `projectId`, `cashOutCount` |
218
201
 
219
202
  ## NatSpec
220
203
 
@@ -270,9 +253,12 @@ uint256 public constant MAX_RESERVED_PERCENT = 10_000;
270
253
 
271
254
  ## Function Calls
272
255
 
273
- Use named parameters for readability when calling functions with 3+ arguments:
256
+ Use named arguments for all function calls with 2 or more arguments — in both `src/` and `script/`:
274
257
 
275
258
  ```solidity
259
+ // Good — named arguments
260
+ token.mint({account: beneficiary, amount: count});
261
+ _transferOwnership({newOwner: address(0), projectId: 0});
276
262
  PERMISSIONS.hasPermission({
277
263
  operator: sender,
278
264
  account: account,
@@ -281,8 +267,18 @@ PERMISSIONS.hasPermission({
281
267
  includeRoot: true,
282
268
  includeWildcardProjectId: true
283
269
  });
270
+
271
+ // Bad — positional arguments with 2+ args
272
+ token.mint(beneficiary, count);
273
+ _transferOwnership(address(0), 0);
284
274
  ```
285
275
 
276
+ Single-argument calls use positional style: `_burn(amount)`.
277
+
278
+ This also applies to constructor calls, struct literals, and inherited/library calls (e.g., OZ `_mint`, `_safeMint`, `safeTransfer`, `allowance`, `Clones.cloneDeterministic`).
279
+
280
+ Named argument keys must use **camelCase** — never underscores. If a function's parameter names use underscores, rename them to camelCase first.
281
+
286
282
  ## Multiline Signatures
287
283
 
288
284
  ```solidity
@@ -333,13 +329,9 @@ Standard config across all repos:
333
329
  solc = '0.8.26'
334
330
  evm_version = 'cancun'
335
331
  optimizer_runs = 200
336
- via_ir = true
337
332
  libs = ["node_modules", "lib"]
338
333
  fs_permissions = [{ access = "read-write", path = "./"}]
339
334
 
340
- [profile.ci_sizes]
341
- optimizer_runs = 200
342
-
343
335
  [fuzz]
344
336
  runs = 4096
345
337
 
@@ -354,10 +346,14 @@ multiline_func_header = "all"
354
346
  wrap_comments = true
355
347
  ```
356
348
 
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)
349
+ **Optional sections (add only when needed):**
350
+ - `[rpc_endpoints]` repos with fork tests. Maps named endpoints to env vars (e.g. `ethereum = "${RPC_ETHEREUM_MAINNET}"`).
351
+ - `[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).
352
+
353
+ **Common variations:**
354
+ - `via_ir = true` when hitting stack-too-deep
355
+ - `optimizer = false` when optimization causes stack-too-deep
356
+ - `optimizer_runs` reduced when deep struct nesting causes stack-too-deep at 200 runs
361
357
 
362
358
  ### CI Workflows
363
359
 
@@ -390,7 +386,7 @@ jobs:
390
386
  env:
391
387
  RPC_ETHEREUM_MAINNET: ${{ secrets.RPC_ETHEREUM_MAINNET }}
392
388
  - name: Check contract sizes
393
- run: FOUNDRY_PROFILE=ci_sizes forge build --sizes --skip "*/test/**" --skip "*/script/**" --skip SphinxUtils
389
+ run: forge build --sizes --skip "*/test/**" --skip "*/script/**" --skip SphinxUtils
394
390
  ```
395
391
 
396
392
  **lint.yml:**
@@ -412,11 +408,60 @@ jobs:
412
408
  run: forge fmt --check
413
409
  ```
414
410
 
411
+ **slither.yml** (repos with `src/` contracts only):
412
+ ```yaml
413
+ name: slither
414
+ on:
415
+ pull_request:
416
+ branches:
417
+ - main
418
+ push:
419
+ branches:
420
+ - main
421
+ jobs:
422
+ analyze:
423
+ runs-on: ubuntu-latest
424
+ steps:
425
+ - uses: actions/checkout@v4
426
+ with:
427
+ submodules: recursive
428
+ - uses: actions/setup-node@v4
429
+ with:
430
+ node-version: latest
431
+ - name: Install npm dependencies
432
+ run: npm install --omit=dev
433
+ - name: Install Foundry
434
+ uses: foundry-rs/foundry-toolchain@v1
435
+ - name: Run slither
436
+ uses: crytic/slither-action@v0.3.1
437
+ with:
438
+ slither-config: slither-ci.config.json
439
+ fail-on: medium
440
+ ```
441
+
442
+ **slither-ci.config.json:**
443
+ ```json
444
+ {
445
+ "detectors_to_exclude": "timestamp,uninitialized-local,naming-convention,solc-version,shadowing-local",
446
+ "exclude_informational": true,
447
+ "exclude_low": false,
448
+ "exclude_medium": false,
449
+ "exclude_high": false,
450
+ "disable_color": false,
451
+ "filter_paths": "(mocks/|test/|node_modules/|lib/)",
452
+ "legacy_ast": false
453
+ }
454
+ ```
455
+
456
+ **Variations:**
457
+ - 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.
458
+ - 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.
459
+
415
460
  ### package.json
416
461
 
417
462
  ```json
418
463
  {
419
- "name": "@bannynet/core-v6",
464
+ "name": "@bananapus/package-name-v6",
420
465
  "version": "x.x.x",
421
466
  "license": "MIT",
422
467
  "repository": { "type": "git", "url": "git+https://github.com/Org/repo.git" },
@@ -436,13 +481,62 @@ jobs:
436
481
 
437
482
  ### remappings.txt
438
483
 
439
- Every repo has a `remappings.txt`. Minimal content:
484
+ Every repo has a `remappings.txt` as the **single source of truth** for import remappings. Never add remappings to `foundry.toml`.
485
+
486
+ **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.
487
+
488
+ **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.
489
+
490
+ **Minimal content** (most repos):
440
491
 
441
492
  ```
442
- @sphinx-labs/contracts/=lib/sphinx/packages/contracts/contracts/foundry
493
+ forge-std/=lib/forge-std/src/
443
494
  ```
444
495
 
445
- Additional mappings as needed for repo-specific dependencies.
496
+ Only add extra remappings for:
497
+ - **`forge-std`** — always needed (git submodule with `src/` subdirectory)
498
+ - **Repo-specific `lib/` submodules** that have no npm package (e.g., `hookmate/=lib/hookmate/src/`)
499
+ - **Symlinked npm packages** — need explicit `@scope/package/=node_modules/@scope/package/` entries
500
+ - **Nested transitive deps** — e.g., `@chainlink/contracts-ccip/` nested inside `@bananapus/suckers-v6/node_modules/`
501
+
502
+ **Never add remappings for:**
503
+ - npm packages that match their import path and are installed as real directories — they auto-resolve
504
+ - Short-form aliases (e.g., `@bananapus/core/` → `@bananapus/core-v6/src/`) — fix the import instead
505
+ - Packages available via npm that are also git submodules — remove the submodule, use npm
506
+
507
+ **Import path convention:**
508
+
509
+ | Package | Import path | Resolves to |
510
+ |---------|------------|-------------|
511
+ | `@bananapus/core-v6` | `@bananapus/core-v6/src/libraries/JBConstants.sol` | `node_modules/@bananapus/core-v6/src/...` |
512
+ | `@openzeppelin/contracts` | `@openzeppelin/contracts/token/ERC20/IERC20.sol` | `node_modules/@openzeppelin/contracts/...` |
513
+ | `@uniswap/v4-core` | `@uniswap/v4-core/src/interfaces/IPoolManager.sol` | `node_modules/@uniswap/v4-core/src/...` |
514
+
515
+ ### Linting
516
+
517
+ Solar (Foundry's built-in linter) runs automatically during `forge build`. It scans all `.sol` files in `libs` directories, including `node_modules`.
518
+
519
+ **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.
520
+
521
+ ### Fork Tests
522
+
523
+ 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.
524
+
525
+ ```solidity
526
+ function setUp() public {
527
+ vm.createSelectFork("ethereum");
528
+ // ... setup code
529
+ }
530
+ ```
531
+
532
+ The endpoint name (e.g. `"ethereum"`) maps to an env var via `foundry.toml`:
533
+
534
+ ```toml
535
+ [rpc_endpoints]
536
+ ethereum = "${RPC_ETHEREUM_MAINNET}"
537
+ ```
538
+
539
+ For multi-chain fork tests, add all needed endpoints.
446
540
 
447
541
  ### Formatting
448
542
 
@@ -453,15 +547,6 @@ Run `forge fmt` before committing. The `[fmt]` config in `foundry.toml` enforces
453
547
 
454
548
  CI checks formatting via `forge fmt --check`.
455
549
 
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
550
  ### Branching
466
551
 
467
552
  - `main` is the primary branch
@@ -479,4 +564,8 @@ Fork tests require `RPC_ETHEREUM_MAINNET` — they fail if it's missing.
479
564
 
480
565
  ### Contract Size Checks
481
566
 
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.
567
+ 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`.
568
+
569
+ ## Repo-Specific Deviations
570
+
571
+ 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.8",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,12 +20,14 @@
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",
25
- "@bananapus/router-terminal-v6": "^0.0.6",
26
- "@bananapus/suckers-v6": "^0.0.7",
27
- "@openzeppelin/contracts": "5.2.0",
28
- "@rev-net/core-v6": "^0.0.6",
23
+ "@bananapus/721-hook-v6": "^0.0.16",
24
+ "@bananapus/core-v6": "^0.0.16",
25
+ "@bananapus/permission-ids-v6": "^0.0.9",
26
+ "@bananapus/router-terminal-v6": "^0.0.11",
27
+ "@bananapus/suckers-v6": "^0.0.10",
28
+ "@croptop/core-v6": "^0.0.15",
29
+ "@openzeppelin/contracts": "^5.6.1",
30
+ "@rev-net/core-v6": "^0.0.12",
29
31
  "keccak": "^3.0.4"
30
32
  },
31
33
  "devDependencies": {
package/remappings.txt CHANGED
@@ -1 +1 @@
1
- @sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry
1
+ forge-std/=lib/forge-std/src/
@@ -5,11 +5,12 @@ import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfi
5
5
  import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
6
6
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
7
7
 
8
- import "./helpers/BannyverseDeploymentLib.sol";
9
- import "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
10
- import "@openzeppelin/contracts/utils/Strings.sol";
11
-
12
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
8
+ import {BannyverseDeployment, BannyverseDeploymentLib} from "./helpers/BannyverseDeploymentLib.sol";
9
+ import {
10
+ RevnetCoreDeployment,
11
+ RevnetCoreDeploymentLib
12
+ } from "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
13
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
13
14
  import {Script} from "forge-std/Script.sol";
14
15
 
15
16
  contract Drop1Script is Script, Sphinx {
@@ -78,13 +79,13 @@ contract Drop1Script is Script, Sphinx {
78
79
  // Get the next tier ID so we can set names and hashes for the new product.
79
80
  uint256 nextTierId = hook.STORE().maxTierIdOf(address(hook)) + 1;
80
81
 
81
- hook.adjustTiers(products, new uint256[](0));
82
+ hook.adjustTiers({tiersToAdd: products, tierIdsToRemove: new uint256[](0)});
82
83
 
83
84
  // Build the product IDs array for the newly added tier(s).
84
85
  uint256[] memory productIds = new uint256[](1);
85
86
  productIds[0] = nextTierId;
86
87
 
87
- bannyverse.resolver.setSvgHashesOf(productIds, svgHashes);
88
- bannyverse.resolver.setProductNames(productIds, names);
88
+ bannyverse.resolver.setSvgHashesOf({upcs: productIds, svgHashes: svgHashes});
89
+ bannyverse.resolver.setProductNames({upcs: productIds, names: names});
89
90
  }
90
91
  }
@@ -1,18 +1,21 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.26;
3
3
 
4
- import "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
5
- import "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
6
- import "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
7
- import "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
8
- import "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
4
+ import {Hook721Deployment, Hook721DeploymentLib} from "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
5
+ import {CoreDeployment, CoreDeploymentLib} from "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
6
+ import {SuckerDeployment, SuckerDeploymentLib} from "@bananapus/suckers-v6/script/helpers/SuckerDeploymentLib.sol";
7
+ import {
8
+ RouterTerminalDeployment,
9
+ RouterTerminalDeploymentLib
10
+ } from "@bananapus/router-terminal-v6/script/helpers/RouterTerminalDeploymentLib.sol";
11
+ import {
12
+ RevnetCoreDeployment,
13
+ RevnetCoreDeploymentLib
14
+ } from "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
9
15
 
10
16
  import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
11
17
  import {JB721InitTiersConfig} from "@bananapus/721-hook-v6/src/structs/JB721InitTiersConfig.sol";
12
18
  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";
15
- import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
16
19
  import {IJBSplitHook} from "@bananapus/core-v6/src/interfaces/IJBSplitHook.sol";
17
20
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
18
21
  import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
@@ -23,14 +26,16 @@ import {JBTokenMapping} from "@bananapus/suckers-v6/src/structs/JBTokenMapping.s
23
26
  import {REVAutoIssuance} from "@rev-net/core-v6/src/structs/REVAutoIssuance.sol";
24
27
  import {REVConfig} from "@rev-net/core-v6/src/structs/REVConfig.sol";
25
28
  import {REVCroptopAllowedPost} from "@rev-net/core-v6/src/structs/REVCroptopAllowedPost.sol";
29
+ import {REVBaseline721HookConfig} from "@rev-net/core-v6/src/structs/REVBaseline721HookConfig.sol";
26
30
  import {REVDeploy721TiersHookConfig} from "@rev-net/core-v6/src/structs/REVDeploy721TiersHookConfig.sol";
27
31
  import {REVDescription} from "@rev-net/core-v6/src/structs/REVDescription.sol";
32
+ import {REV721TiersHookFlags} from "@rev-net/core-v6/src/structs/REV721TiersHookFlags.sol";
28
33
  import {REVStageConfig} from "@rev-net/core-v6/src/structs/REVStageConfig.sol";
29
34
  import {REVSuckerDeploymentConfig} from "@rev-net/core-v6/src/structs/REVSuckerDeploymentConfig.sol";
30
35
  import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
31
36
  import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
32
37
 
33
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
38
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
34
39
  import {Script} from "forge-std/Script.sol";
35
40
 
36
41
  import {Banny721TokenUriResolver} from "./../src/Banny721TokenUriResolver.sol";
@@ -56,27 +61,27 @@ contract DeployScript is Script, Sphinx {
56
61
 
57
62
  BannyverseRevnetConfig bannyverseConfig;
58
63
 
59
- uint32 PREMINT_CHAIN_ID = 1;
60
- bytes32 ERC20_SALT = "_BAN_ERC20V6_";
61
- bytes32 SUCKER_SALT = "_BAN_SUCKERV6_";
62
- bytes32 HOOK_SALT = "_BAN_HOOKV6_";
63
- bytes32 RESOLVER_SALT = "_BAN_RESOLVERV6_";
64
- string NAME = "Banny Network";
65
- string SYMBOL = "BAN";
66
- string PROJECT_URI = "ipfs://Qme34ww9HuwnsWF6sYDpDfpSdYHpPCGsEyJULk1BikCVYp";
67
- string BASE_URI = "ipfs://";
68
- uint32 NATIVE_CURRENCY = uint32(uint160(JBConstants.NATIVE_TOKEN));
69
- uint32 ETH_CURRENCY = JBCurrencyIds.ETH;
70
- uint8 DECIMALS = 18;
71
- uint256 DECIMAL_MULTIPLIER = 10 ** DECIMALS;
72
- uint24 BANNY_BODY_CATEGORY = 0;
73
- address OPERATOR;
74
- address TRUSTED_FORWARDER;
75
- uint48 BAN_START_TIME = 1_740_435_044;
76
- uint104 BAN_MAINNET_AUTO_ISSUANCE_ = 545_296_034_092_246_678_345_976;
77
- uint104 BAN_BASE_AUTO_ISSUANCE_ = 10_097_684_379_816_492_953_872;
78
- uint104 BAN_OP_AUTO_ISSUANCE_ = 328_366_065_858_064_488_000;
79
- uint104 BAN_ARB_AUTO_ISSUANCE_ = 2_825_980_000_000_000_000_000;
64
+ uint32 constant PREMINT_CHAIN_ID = 1;
65
+ bytes32 constant ERC20_SALT = "_BAN_ERC20V6_";
66
+ bytes32 constant SUCKER_SALT = "_BAN_SUCKERV6_";
67
+ bytes32 constant HOOK_SALT = "_BAN_HOOKV6_";
68
+ bytes32 constant RESOLVER_SALT = "_BAN_RESOLVERV6_";
69
+ string constant NAME = "Banny Network";
70
+ string constant SYMBOL = "BAN";
71
+ string constant PROJECT_URI = "ipfs://Qme34ww9HuwnsWF6sYDpDfpSdYHpPCGsEyJULk1BikCVYp";
72
+ string constant BASE_URI = "ipfs://";
73
+ uint32 constant NATIVE_CURRENCY = uint32(uint160(JBConstants.NATIVE_TOKEN));
74
+ uint32 constant ETH_CURRENCY = JBCurrencyIds.ETH;
75
+ uint8 constant DECIMALS = 18;
76
+ uint256 constant DECIMAL_MULTIPLIER = 10 ** DECIMALS;
77
+ uint24 constant BANNY_BODY_CATEGORY = 0;
78
+ address operator;
79
+ address trustedForwarder;
80
+ uint48 constant BAN_START_TIME = 1_740_435_044;
81
+ uint104 constant BAN_MAINNET_AUTO_ISSUANCE = 545_296_034_092_246_678_345_976;
82
+ uint104 constant BAN_BASE_AUTO_ISSUANCE = 10_097_684_379_816_492_953_872;
83
+ uint104 constant BAN_OP_AUTO_ISSUANCE = 328_366_065_858_064_488_000;
84
+ uint104 constant BAN_ARB_AUTO_ISSUANCE = 2_825_980_000_000_000_000_000;
80
85
 
81
86
  function configureSphinx() public override {
82
87
  sphinxConfig.projectName = "banny-core-v6";
@@ -86,7 +91,7 @@ contract DeployScript is Script, Sphinx {
86
91
 
87
92
  function run() public {
88
93
  // Get the operator address.
89
- OPERATOR = safeAddress();
94
+ operator = safeAddress();
90
95
 
91
96
  // Get the deployment addresses for the nana CORE for this chain.
92
97
  // We want to do this outside of the `sphinx` modifier.
@@ -113,7 +118,7 @@ contract DeployScript is Script, Sphinx {
113
118
  )
114
119
  );
115
120
 
116
- TRUSTED_FORWARDER = core.controller.trustedForwarder();
121
+ trustedForwarder = core.controller.trustedForwarder();
117
122
 
118
123
  bannyverseConfig = getBannyverseRevnetConfig();
119
124
 
@@ -142,7 +147,7 @@ contract DeployScript is Script, Sphinx {
142
147
  splits[0] = JBSplit({
143
148
  percent: JBConstants.SPLITS_TOTAL_PERCENT,
144
149
  projectId: 0,
145
- beneficiary: payable(OPERATOR),
150
+ beneficiary: payable(operator),
146
151
  preferAddToBalance: false,
147
152
  lockedUntil: 0,
148
153
  hook: IJBSplitHook(address(0))
@@ -153,16 +158,17 @@ contract DeployScript is Script, Sphinx {
153
158
 
154
159
  {
155
160
  REVAutoIssuance[] memory autoIssuances = new REVAutoIssuance[](4);
156
- autoIssuances[0] = REVAutoIssuance({chainId: 1, count: BAN_MAINNET_AUTO_ISSUANCE_, beneficiary: OPERATOR});
157
- autoIssuances[1] = REVAutoIssuance({chainId: 8453, count: BAN_BASE_AUTO_ISSUANCE_, beneficiary: OPERATOR});
158
- autoIssuances[2] = REVAutoIssuance({chainId: 10, count: BAN_OP_AUTO_ISSUANCE_, beneficiary: OPERATOR});
159
- autoIssuances[3] = REVAutoIssuance({chainId: 42_161, count: BAN_ARB_AUTO_ISSUANCE_, beneficiary: OPERATOR});
161
+ autoIssuances[0] = REVAutoIssuance({chainId: 1, count: BAN_MAINNET_AUTO_ISSUANCE, beneficiary: operator});
162
+ autoIssuances[1] = REVAutoIssuance({chainId: 8453, count: BAN_BASE_AUTO_ISSUANCE, beneficiary: operator});
163
+ autoIssuances[2] = REVAutoIssuance({chainId: 10, count: BAN_OP_AUTO_ISSUANCE, beneficiary: operator});
164
+ autoIssuances[3] = REVAutoIssuance({chainId: 42_161, count: BAN_ARB_AUTO_ISSUANCE, beneficiary: operator});
160
165
 
161
166
  stageConfigurations[0] = REVStageConfig({
162
167
  startsAtOrAfter: BAN_START_TIME,
163
168
  autoIssuances: autoIssuances,
164
169
  splitPercent: 3800, // 38%
165
170
  splits: splits,
171
+ // forge-lint: disable-next-line(unsafe-typecast)
166
172
  initialIssuance: uint112(10_000 * DECIMAL_MULTIPLIER),
167
173
  issuanceCutFrequency: 60 days,
168
174
  issuanceCutPercent: 380_000_000, // 38%,
@@ -174,7 +180,10 @@ contract DeployScript is Script, Sphinx {
174
180
  {
175
181
  REVAutoIssuance[] memory autoIssuances = new REVAutoIssuance[](1);
176
182
  autoIssuances[0] = REVAutoIssuance({
177
- chainId: PREMINT_CHAIN_ID, count: uint104(1_000_000 * DECIMAL_MULTIPLIER), beneficiary: OPERATOR
183
+ // forge-lint: disable-next-line(unsafe-typecast)
184
+ chainId: PREMINT_CHAIN_ID,
185
+ count: uint104(1_000_000 * DECIMAL_MULTIPLIER),
186
+ beneficiary: operator
178
187
  });
179
188
 
180
189
  // decrease by a smaller percent more frequently. 30 days, 7%-ish.
@@ -204,9 +213,9 @@ contract DeployScript is Script, Sphinx {
204
213
  });
205
214
 
206
215
  REVConfig memory revnetConfiguration = REVConfig({
207
- description: REVDescription(NAME, SYMBOL, PROJECT_URI, ERC20_SALT),
216
+ description: REVDescription({name: NAME, ticker: SYMBOL, uri: PROJECT_URI, salt: ERC20_SALT}),
208
217
  baseCurrency: ETH_CURRENCY,
209
- splitOperator: OPERATOR,
218
+ splitOperator: operator,
210
219
  stageConfigurations: stageConfigurations
211
220
  });
212
221
 
@@ -219,7 +228,7 @@ contract DeployScript is Script, Sphinx {
219
228
  votingUnits: 0,
220
229
  reserveFrequency: 0,
221
230
  reserveBeneficiary: address(0),
222
- encodedIPFSUri: bytes32(""),
231
+ encodedIPFSUri: bytes32(0),
223
232
  category: BANNY_BODY_CATEGORY,
224
233
  discountPercent: 0,
225
234
  cannotIncreaseDiscountPercent: true,
@@ -237,7 +246,7 @@ contract DeployScript is Script, Sphinx {
237
246
  votingUnits: 0,
238
247
  reserveFrequency: 0,
239
248
  reserveBeneficiary: address(0),
240
- encodedIPFSUri: bytes32(""),
249
+ encodedIPFSUri: bytes32(0),
241
250
  category: BANNY_BODY_CATEGORY,
242
251
  discountPercent: 0,
243
252
  cannotIncreaseDiscountPercent: true,
@@ -255,7 +264,7 @@ contract DeployScript is Script, Sphinx {
255
264
  votingUnits: 0,
256
265
  reserveFrequency: 0,
257
266
  reserveBeneficiary: address(0),
258
- encodedIPFSUri: bytes32(""),
267
+ encodedIPFSUri: bytes32(0),
259
268
  category: BANNY_BODY_CATEGORY,
260
269
  discountPercent: 0,
261
270
  cannotIncreaseDiscountPercent: true,
@@ -273,7 +282,7 @@ contract DeployScript is Script, Sphinx {
273
282
  votingUnits: 0,
274
283
  reserveFrequency: 0,
275
284
  reserveBeneficiary: address(0),
276
- encodedIPFSUri: bytes32(""),
285
+ encodedIPFSUri: bytes32(0),
277
286
  category: BANNY_BODY_CATEGORY,
278
287
  discountPercent: 0,
279
288
  cannotIncreaseDiscountPercent: true,
@@ -331,30 +340,27 @@ contract DeployScript is Script, Sphinx {
331
340
  terminalConfigurations: terminalConfigurations,
332
341
  suckerDeploymentConfiguration: suckerDeploymentConfiguration,
333
342
  hookConfiguration: REVDeploy721TiersHookConfig({
334
- baseline721HookConfiguration: JBDeploy721TiersHookConfig({
343
+ baseline721HookConfiguration: REVBaseline721HookConfig({
335
344
  name: "Banny Retail",
336
345
  symbol: "BANNY",
337
346
  baseUri: BASE_URI,
338
347
  tokenUriResolver: IJB721TokenUriResolver(address(0)), // This will be replaced once we know the
339
348
  // address.
340
349
  contractUri: "https://jbm.infura-ipfs.io/ipfs/Qmd2hgb1E4caEB51VvoC3GvonhwkCoVyXjJ3zqsCxHPTKK",
341
- tiersConfig: JB721InitTiersConfig({
342
- tiers: tiers, currency: ETH_CURRENCY, decimals: DECIMALS, prices: core.prices
343
- }),
350
+ tiersConfig: JB721InitTiersConfig({tiers: tiers, currency: ETH_CURRENCY, decimals: DECIMALS}),
344
351
  reserveBeneficiary: address(0),
345
- flags: JB721TiersHookFlags({
352
+ flags: REV721TiersHookFlags({
346
353
  noNewTiersWithReserves: false,
347
354
  noNewTiersWithVotes: false,
348
355
  noNewTiersWithOwnerMinting: false,
349
- preventOverspending: false,
350
- issueTokensForSplits: false
356
+ preventOverspending: false
351
357
  })
352
358
  }),
353
359
  salt: HOOK_SALT,
354
- splitOperatorCanAdjustTiers: true,
355
- splitOperatorCanUpdateMetadata: true,
356
- splitOperatorCanMint: true,
357
- splitOperatorCanIncreaseDiscountPercent: true
360
+ preventSplitOperatorAdjustingTiers: false,
361
+ preventSplitOperatorUpdatingMetadata: false,
362
+ preventSplitOperatorMinting: false,
363
+ preventSplitOperatorIncreasingDiscountPercent: false
358
364
  })
359
365
  });
360
366
  }
@@ -363,15 +369,15 @@ contract DeployScript is Script, Sphinx {
363
369
  // Deploy the Banny URI Resolver.
364
370
  Banny721TokenUriResolver resolver;
365
371
 
366
- string memory _BANNY_BODY =
372
+ string memory bannyBodySvg =
367
373
  '<g class="a1"><path d="M173 53h4v17h-4z"/></g><g class="a2"><path d="M167 57h3v10h-3z"/><path d="M169 53h4v17h-4z"/></g><g class="a3"><path d="M167 53h3v4h-3z"/><path d="M163 57h4v10h-4z"/><path d="M167 67h3v3h-3z"/></g><g class="b1"><path d="M213 253h-3v-3-3h-3v-7-3h-4v-10h-3v-7-7-3h-3v-73h-4v-10h-3v-10h-3v-7h-4v-7h-3v-3h-3v-3h-4v10h4v10h3v10h3v3h4v7 3 70 3h3v7h3v20h4v7h3v3h3v3h4v4h3v3h3v-3-4z"/><path d="M253 307v-4h-3v-3h-3v-3h-4v-4h-3v-3h-3v-3h-4v-4h-3v-3h-3v-3h-4v-4h-3v-6h-3v-7h-4v17h4v3h3v3h3 4v4h3v3h3v3h4v4h3v3h3v3h4v4h3v3h3v3h4v-6h-4z"/></g><g class="b2"><path d="M250 310v-3h-3v-4h-4v-3h-3v-3h-3v-4h-4v-3h-3v-3h-3v-4h-7v-3h-3v-3h-4v-17h-3v-3h-3v-4h-4v-3h-3v-3h-3v-7h-4v-20h-3v-7h-3v-73-3-7h-4v-3h-3v-10h-3v-10h-4V70h-3v-3l-3 100 3-100v40h-3v10h-4v6h-3v14h-3v3 13h-4v44h4v16h3v14h3v13h4v10h3v7h3v3h4v3h3v4h3v3h4v3h3v4h3v3h4v3h3v7h7v7h6v3h7v3h7v4h13v3h3v3h10v-3h-3zm-103-87v-16h3v-10h-3v6h-4v17h-3v10h3v-7h4z"/><path d="M143 230h4v7h-4zm4 10h3v3h-3zm3 7h3v3h-3zm3 6h4v4h-4z"/><path d="M163 257h-6v3h3v3h3v4h4v-4-3h-4v-3z"/></g><g class="b3"><path d="M143 197v6h4v-6h6v-44h4v-16h3v-14h3v-6h4v-10h3V97h-7v6h-3v4h-3v3h-4v3h-3v4 3h-3v3 4h-4v10h-3v16 4h-3v46h3v-6h3z"/><path d="M140 203h3v17h-3z"/><path d="M137 220h3v10h-3z"/><path d="M153 250h-3v-7h-3v-6h-4v-7h-3v10h3v7h4v6h3v4h3v-7zm-3 10h3v7h-3z"/><path d="M147 257h3v3h-3zm6 0h4v3h-4z"/><path d="M160 263v-3h-3v3 7h6v-7h-3zm-10-56v16h-3v7h3v10h3v7h4v6h6v4h7v-4-3h-3v-10h-4v-13h-3v-14h-3v-16h-4v10h-3z"/><path d="M243 313v-3h-3v-3h-10-3v-4h-7v-3h-7v-3h-6v-7h-7v-7h-3v-3h-4v-3h-3v-4h-3v-3h-4v-3h-3v-4h-3v-3h-4v-3h-3v10h-3v3h-4v3h-3v7h3v7h4v6h3v5h4v3h6v3h3v3h4 3v3h3 4v3h3 3v4h10v3h7 7 3v3h10 3v-3h10v-3h4v-4h-14z"/></g><g class="b4"><path d="M183 130h4v7h-4z"/><path d="M180 127h3v3h-3zm-27-4h4v7h-4z"/><path d="M157 117h3v6h-3z"/><path d="M160 110h3v7h-3z"/><path d="M163 107h4v3h-4zm-3 83h3v7h-3z"/><path d="M163 187h4v3h-4zm20 0h7v3h-7z"/><path d="M180 190h3v3h-3zm10-7h3v4h-3z"/><path d="M193 187h4v6h-4zm-20 53h4v7h-4z"/><path d="M177 247h3v6h-3z"/><path d="M180 253h3v7h-3z"/><path d="M183 260h7v3h-7z"/><path d="M190 263h3v4h-3zm0-20h3v4h-3z"/><path d="M187 240h3v3h-3z"/><path d="M190 237h3v3h-3zm13 23h4v3h-4z"/><path d="M207 263h3v7h-3z"/><path d="M210 270h3v3h-3zm-10 7h3v6h-3z"/><path d="M203 283h4v7h-4z"/><path d="M207 290h6v3h-6z"/></g><g class="o"><path d="M133 157h4v50h-4zm0 63h4v10h-4zm27-163h3v10h-3z"/><path d="M163 53h4v4h-4z"/><path d="M167 50h10v3h-10z"/><path d="M177 53h3v17h-3z"/><path d="M173 70h4v27h-4zm-6 0h3v27h-3z"/><path d="M163 67h4v3h-4zm0 30h4v3h-4z"/><path d="M160 100h3v3h-3z"/><path d="M157 103h3v4h-3z"/><path d="M153 107h4v3h-4z"/><path d="M150 110h3v3h-3z"/><path d="M147 113h3v7h-3z"/><path d="M143 120h4v7h-4z"/><path d="M140 127h3v10h-3z"/><path d="M137 137h3v20h-3zm56-10h4v10h-4z"/><path d="M190 117h3v10h-3z"/><path d="M187 110h3v7h-3z"/><path d="M183 103h4v7h-4z"/><path d="M180 100h3v3h-3z"/><path d="M177 97h3v3h-3zm-40 106h3v17h-3zm0 27h3v10h-3zm10 30h3v7h-3z"/><path d="M150 257v-4h-3v-6h-4v-7h-3v10h3v10h4v-3h3z"/><path d="M150 257h3v3h-3z"/><path d="M163 273v-3h-6v-10h-4v7h-3v3h3v3h4v7h3v-7h3z"/><path d="M163 267h4v3h-4z"/><path d="M170 257h-3-4v3h4v7h3v-10z"/><path d="M157 253h6v4h-6z"/><path d="M153 247h4v6h-4z"/><path d="M150 240h3v7h-3z"/><path d="M147 230h3v10h-3zm13 50h3v7h-3z"/><path d="M143 223h4v7h-4z"/><path d="M147 207h3v16h-3z"/><path d="M150 197h3v10h-3zm-10 0h3v6h-3zm50 113h7v3h-7zm23 10h17v3h-17z"/><path d="M230 323h13v4h-13z"/><path d="M243 320h10v3h-10z"/><path d="M253 317h4v3h-4z"/><path d="M257 307h3v10h-3z"/><path d="M253 303h4v4h-4z"/><path d="M250 300h3v3h-3z"/><path d="M247 297h3v3h-3z"/><path d="M243 293h4v4h-4z"/><path d="M240 290h3v3h-3z"/><path d="M237 287h3v3h-3z"/><path d="M233 283h4v4h-4z"/><path d="M230 280h3v3h-3z"/><path d="M227 277h3v3h-3z"/><path d="M223 273h4v4h-4z"/><path d="M220 267h3v6h-3z"/><path d="M217 260h3v7h-3z"/><path d="M213 253h4v7h-4z"/><path d="M210 247h3v6h-3z"/><path d="M207 237h3v10h-3z"/><path d="M203 227h4v10h-4zm-40 60h4v6h-4zm24 20h3v3h-3z"/><path d="M167 293h3v5h-3zm16 14h4v3h-4z"/><path d="M170 298h4v3h-4zm10 6h3v3h-3z"/><path d="M174 301h6v3h-6zm23 12h6v4h-6z"/><path d="M203 317h10v3h-10zm-2-107v-73h-4v73h3v17h3v-17h-2z"/></g><g class="o"><path d="M187 307v-4h3v-6h-3v-4h-4v-3h-3v-3h-7v-4h-6v4h-4v3h4v27h-4v13h-3v10h-4v7h4v3h3 10 14v-3h-4v-4h-3v-3h-3v-3h-4v-7h4v-10h3v-7h3v-3h7v-3h-3zm16 10v-4h-6v17h-4v10h-3v7h3v3h4 6 4 3 14v-3h-4v-4h-7v-3h-3v-3h-3v-10h3v-7h3v-3h-10z"/></g>';
368
- string memory _DEFAULT_NECKLACE =
374
+ string memory defaultNecklaceSvg =
369
375
  '<g class="o"><path d="M190 173h-37v-3h-10v-4h-6v4h3v3h-3v4h6v3h10v4h37v-4h3v-3h-3v-4zm-40 4h-3v-4h3v4zm7 3v-3h3v3h-3zm6 0v-3h4v3h-4zm7 0v-3h3v3h-3zm7 0v-3h3v3h-3zm10 0h-4v-3h4v3z"/><path d="M190 170h3v3h-3z"/><path d="M193 166h4v4h-4zm0 7h4v4h-4z"/></g><g class="w"><path d="M137 170h3v3h-3zm10 3h3v4h-3zm10 4h3v3h-3zm6 0h4v3h-4zm7 0h3v3h-3zm7 0h3v3h-3zm6 0h4v3h-4zm7-4h3v4h-3z"/><path d="M193 170h4v3h-4z"/></g>';
370
- string memory _DEFAULT_MOUTH =
376
+ string memory defaultMouthSvg =
371
377
  '<g class="o"><path d="M183 160v-4h-20v4h-3v3h3v4h24v-7h-4zm-13 3v-3h10v3h-10z" fill="#ad71c8"/><path d="M170 160h10v3h-10z"/></g>';
372
- string memory _DEFAULT_STANDARD_EYES =
378
+ string memory defaultStandardEyesSvg =
373
379
  '<g class="o"><path d="M177 140v3h6v11h10v-11h4v-3h-20z"/><path d="M153 140v3h7v8 3h7 3v-11h3v-3h-20z"/></g><g class="w"><path d="M153 143h7v4h-7z"/><path d="M157 147h3v3h-3zm20-4h6v4h-6z"/><path d="M180 147h3v3h-3z"/></g>';
374
- string memory _DEFAULT_ALIEN_EYES =
380
+ string memory defaultAlienEyesSvg =
375
381
  '<g class="o"><path d="M190 127h3v3h-3zm3 13h4v3h-4zm-42 0h6v6h-6z"/><path d="M151 133h3v7h-3zm10 0h6v4h-6z"/><path d="M157 137h17v6h-17zm3 13h14v3h-14zm17-13h7v16h-7z"/><path d="M184 137h6v6h-6zm0 10h10v6h-10z"/><path d="M187 143h10v4h-10z"/><path d="M190 140h3v3h-3zm-6-10h3v7h-3z"/><path d="M187 130h6v3h-6zm-36 0h10v3h-10zm16 13h7v7h-7zm-10 0h7v7h-7z"/><path d="M164 147h3v3h-3zm29-20h4v6h-4z"/><path d="M194 133h3v7h-3z"/></g><g class="w"><path d="M154 133h7v4h-7z"/><path d="M154 137h3v3h-3zm10 6h3v4h-3zm20 0h3v4h-3zm3-10h7v4h-7z"/><path d="M190 137h4v3h-4z"/></g>';
376
382
  {
377
383
  // Perform the check for the resolver..
@@ -379,40 +385,42 @@ contract DeployScript is Script, Sphinx {
379
385
  RESOLVER_SALT,
380
386
  type(Banny721TokenUriResolver).creationCode,
381
387
  abi.encode(
382
- _BANNY_BODY,
383
- _DEFAULT_NECKLACE,
384
- _DEFAULT_MOUTH,
385
- _DEFAULT_STANDARD_EYES,
386
- _DEFAULT_ALIEN_EYES,
387
- OPERATOR,
388
- TRUSTED_FORWARDER
388
+ bannyBodySvg,
389
+ defaultNecklaceSvg,
390
+ defaultMouthSvg,
391
+ defaultStandardEyesSvg,
392
+ defaultAlienEyesSvg,
393
+ operator,
394
+ trustedForwarder
389
395
  )
390
396
  );
391
397
  // Deploy it if it has not been deployed yet.
392
398
  resolver = !_resolverIsDeployed
393
- ? new Banny721TokenUriResolver{salt: RESOLVER_SALT}(
394
- _BANNY_BODY,
395
- _DEFAULT_NECKLACE,
396
- _DEFAULT_MOUTH,
397
- _DEFAULT_STANDARD_EYES,
398
- _DEFAULT_ALIEN_EYES,
399
- OPERATOR,
400
- TRUSTED_FORWARDER
401
- )
399
+ ? new Banny721TokenUriResolver{salt: RESOLVER_SALT}({
400
+ bannyBody: bannyBodySvg,
401
+ defaultNecklace: defaultNecklaceSvg,
402
+ defaultMouth: defaultMouthSvg,
403
+ defaultStandardEyes: defaultStandardEyesSvg,
404
+ defaultAlienEyes: defaultAlienEyesSvg,
405
+ owner: operator,
406
+ trustedForwarder: trustedForwarder
407
+ })
402
408
  : Banny721TokenUriResolver(_resolver);
403
409
  }
404
410
 
405
411
  // Set the resolver's metadata.
406
- resolver.setMetadata(
407
- "A piece of Banny Retail.", "https://retail.banny.eth.shop", "https://bannyverse.infura-ipfs.io/ipfs/"
408
- );
412
+ resolver.setMetadata({
413
+ description: "A piece of Banny Retail.",
414
+ url: "https://retail.banny.eth.shop",
415
+ baseUri: "https://bannyverse.infura-ipfs.io/ipfs/"
416
+ });
409
417
 
410
418
  // Update our config with its address.
411
419
  bannyverseConfig.hookConfiguration.baseline721HookConfiguration.tokenUriResolver = resolver;
412
420
 
413
421
  // Deploy the $BANNY Revnet.
414
422
  revnet.basic_deployer
415
- .deployWith721sFor({
423
+ .deployFor({
416
424
  revnetId: 0,
417
425
  configuration: bannyverseConfig.configuration,
418
426
  terminalConfigurations: bannyverseConfig.terminalConfigurations,
@@ -5,11 +5,12 @@ import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfi
5
5
  import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
6
6
  import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
7
7
 
8
- import "./helpers/BannyverseDeploymentLib.sol";
9
- import "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
10
- import "@openzeppelin/contracts/utils/Strings.sol";
11
-
12
- import {Sphinx} from "@sphinx-labs/contracts/SphinxPlugin.sol";
8
+ import {BannyverseDeployment, BannyverseDeploymentLib} from "./helpers/BannyverseDeploymentLib.sol";
9
+ import {
10
+ RevnetCoreDeployment,
11
+ RevnetCoreDeploymentLib
12
+ } from "@rev-net/core-v6/script/helpers/RevnetCoreDeploymentLib.sol";
13
+ import {Sphinx} from "@sphinx-labs/contracts/contracts/foundry/SphinxPlugin.sol";
13
14
  import {Script} from "forge-std/Script.sol";
14
15
 
15
16
  contract Drop1Script is Script, Sphinx {
@@ -1047,8 +1048,8 @@ contract Drop1Script is Script, Sphinx {
1047
1048
  productIds[i] = i + 5;
1048
1049
  }
1049
1050
 
1050
- hook.adjustTiers(products, new uint256[](0));
1051
- bannyverse.resolver.setSvgHashesOf(productIds, svgHashes);
1052
- bannyverse.resolver.setProductNames(productIds, names);
1051
+ hook.adjustTiers({tiersToAdd: products, tierIdsToRemove: new uint256[](0)});
1052
+ bannyverse.resolver.setSvgHashesOf({upcs: productIds, svgHashes: svgHashes});
1053
+ bannyverse.resolver.setProductNames({upcs: productIds, names: names});
1053
1054
  }
1054
1055
  }
@@ -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;
@@ -16,6 +16,7 @@ struct BannyverseDeployment {
16
16
  library BannyverseDeploymentLib {
17
17
  // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
18
18
  address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
19
+ // forge-lint: disable-next-line(screaming-snake-case-const)
19
20
  Vm internal constant vm = Vm(VM_ADDRESS);
20
21
 
21
22
  function getDeployment(
@@ -35,7 +36,7 @@ library BannyverseDeploymentLib {
35
36
 
36
37
  for (uint256 _i; _i < networks.length; _i++) {
37
38
  if (networks[_i].chainId == chainId) {
38
- return getDeployment(path, networks[_i].name, revnetId);
39
+ return getDeployment({path: path, networkName: networks[_i].name, revnetId: revnetId});
39
40
  }
40
41
  }
41
42
 
@@ -44,7 +45,7 @@ library BannyverseDeploymentLib {
44
45
 
45
46
  function getDeployment(
46
47
  string memory path,
47
- string memory network_name,
48
+ string memory networkName,
48
49
  uint256 revnetId
49
50
  )
50
51
  internal
@@ -52,7 +53,12 @@ library BannyverseDeploymentLib {
52
53
  returns (BannyverseDeployment memory deployment)
53
54
  {
54
55
  deployment.resolver = Banny721TokenUriResolver(
55
- _getDeploymentAddress(path, "banny-core-v6", network_name, "Banny721TokenUriResolver")
56
+ _getDeploymentAddress({
57
+ path: path,
58
+ projectName: "banny-core-v6",
59
+ networkName: networkName,
60
+ contractName: "Banny721TokenUriResolver"
61
+ })
56
62
  );
57
63
 
58
64
  deployment.revnetId = revnetId;
@@ -65,16 +71,17 @@ library BannyverseDeploymentLib {
65
71
  /// @return The address of the contract.
66
72
  function _getDeploymentAddress(
67
73
  string memory path,
68
- string memory project_name,
69
- string memory network_name,
74
+ string memory projectName,
75
+ string memory networkName,
70
76
  string memory contractName
71
77
  )
72
78
  internal
73
79
  view
74
80
  returns (address)
75
81
  {
82
+ // forge-lint: disable-next-line(unsafe-cheatcode)
76
83
  string memory deploymentJson =
77
- vm.readFile(string.concat(path, project_name, "/", network_name, "/", contractName, ".json"));
78
- return stdJson.readAddress(deploymentJson, ".address");
84
+ vm.readFile(string.concat(path, projectName, "/", networkName, "/", contractName, ".json"));
85
+ return stdJson.readAddress({json: deploymentJson, key: ".address"});
79
86
  }
80
87
  }
@@ -7,7 +7,7 @@ import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721
7
7
 
8
8
  library MigrationHelper {
9
9
  /// @notice Get the UPC (tier ID) from a token ID
10
- function _getUPC(address hook, uint256 tokenId) internal view returns (uint256) {
10
+ function _getUpc(address hook, uint256 tokenId) internal view returns (uint256) {
11
11
  IJB721TiersHookStore store = JB721TiersHook(hook).STORE();
12
12
  return store.tierOfTokenId({hook: hook, tokenId: tokenId, includeResolvedUri: false}).id;
13
13
  }
@@ -24,22 +24,24 @@ library MigrationHelper {
24
24
  view
25
25
  {
26
26
  // Get V5 asset token IDs (from V5 hook)
27
- (uint256 v5BackgroundId, uint256[] memory v5OutfitIds) = resolver.assetIdsOf(hookAddress, tokenId);
27
+ (uint256 v5BackgroundId, uint256[] memory v5OutfitIds) =
28
+ resolver.assetIdsOf({hook: hookAddress, bannyBodyId: tokenId});
28
29
  // Get V4 asset token IDs (from V4 hook)
29
- (uint256 v4BackgroundId, uint256[] memory v4OutfitIds) = v4Resolver.assetIdsOf(v4HookAddress, tokenId);
30
+ (uint256 v4BackgroundId, uint256[] memory v4OutfitIds) =
31
+ v4Resolver.assetIdsOf({hook: v4HookAddress, bannyBodyId: tokenId});
30
32
 
31
33
  // Compare background UPCs (not token IDs, since they may differ)
32
- uint256 v5BackgroundUPC = v5BackgroundId == 0 ? 0 : _getUPC(hookAddress, v5BackgroundId);
33
- uint256 v4BackgroundUPC = v4BackgroundId == 0 ? 0 : _getUPC(v4HookAddress, v4BackgroundId);
34
+ uint256 v5BackgroundUpc = v5BackgroundId == 0 ? 0 : _getUpc({hook: hookAddress, tokenId: v5BackgroundId});
35
+ uint256 v4BackgroundUpc = v4BackgroundId == 0 ? 0 : _getUpc({hook: v4HookAddress, tokenId: v4BackgroundId});
34
36
 
35
- bool matches = v5BackgroundUPC == v4BackgroundUPC && v5OutfitIds.length == v4OutfitIds.length;
37
+ bool matches = v5BackgroundUpc == v4BackgroundUpc && v5OutfitIds.length == v4OutfitIds.length;
36
38
 
37
39
  if (matches) {
38
40
  // Compare outfit UPCs
39
41
  for (uint256 i = 0; i < v5OutfitIds.length; i++) {
40
- uint256 v5OutfitUPC = _getUPC(hookAddress, v5OutfitIds[i]);
41
- uint256 v4OutfitUPC = _getUPC(v4HookAddress, v4OutfitIds[i]);
42
- if (v5OutfitUPC != v4OutfitUPC) {
42
+ uint256 v5OutfitUpc = _getUpc({hook: hookAddress, tokenId: v5OutfitIds[i]});
43
+ uint256 v4OutfitUpc = _getUpc({hook: v4HookAddress, tokenId: v4OutfitIds[i]});
44
+ if (v5OutfitUpc != v4OutfitUpc) {
43
45
  matches = false;
44
46
  break;
45
47
  }
@@ -48,17 +50,17 @@ library MigrationHelper {
48
50
 
49
51
  if (!matches) {
50
52
  // Try fallback resolver
51
- (v4BackgroundId, v4OutfitIds) = fallbackV4Resolver.assetIdsOf(v4HookAddress, tokenId);
52
- v4BackgroundUPC = v4BackgroundId == 0 ? 0 : _getUPC(v4HookAddress, v4BackgroundId);
53
+ (v4BackgroundId, v4OutfitIds) = fallbackV4Resolver.assetIdsOf({hook: v4HookAddress, bannyBodyId: tokenId});
54
+ v4BackgroundUpc = v4BackgroundId == 0 ? 0 : _getUpc({hook: v4HookAddress, tokenId: v4BackgroundId});
53
55
 
54
56
  require(
55
- v5BackgroundUPC == v4BackgroundUPC && v5OutfitIds.length == v4OutfitIds.length, "V4/V5 asset mismatch"
57
+ v5BackgroundUpc == v4BackgroundUpc && v5OutfitIds.length == v4OutfitIds.length, "V4/V5 asset mismatch"
56
58
  );
57
59
 
58
60
  for (uint256 i = 0; i < v5OutfitIds.length; i++) {
59
- uint256 v5OutfitUPC = _getUPC(hookAddress, v5OutfitIds[i]);
60
- uint256 v4OutfitUPC = _getUPC(v4HookAddress, v4OutfitIds[i]);
61
- require(v5OutfitUPC == v4OutfitUPC, "V4/V5 asset mismatch");
61
+ uint256 v5OutfitUpc = _getUpc({hook: hookAddress, tokenId: v5OutfitIds[i]});
62
+ uint256 v4OutfitUpc = _getUpc({hook: v4HookAddress, tokenId: v4OutfitIds[i]});
63
+ require(v5OutfitUpc == v4OutfitUpc, "V4/V5 asset mismatch");
62
64
  }
63
65
  }
64
66
  }
@@ -91,14 +93,14 @@ library MigrationHelper {
91
93
  // Check if this tier is owned by the fallback resolver in V4
92
94
  // If so, skip verification (these are now owned by rightful owners in V5)
93
95
  uint256 v4FallbackResolverBalance =
94
- v4Store.tierBalanceOf(v4HookAddress, v4FallbackResolverAddress, tierId);
96
+ v4Store.tierBalanceOf({hook: v4HookAddress, owner: v4FallbackResolverAddress, tierId: tierId});
95
97
  if (v4FallbackResolverBalance > 0) {
96
98
  continue;
97
99
  }
98
100
 
99
101
  // Get V4 and V5 tier balances for this owner and tier
100
- uint256 v4Balance = v4Store.tierBalanceOf(v4HookAddress, owner, tierId);
101
- uint256 v5Balance = v5Store.tierBalanceOf(hookAddress, owner, tierId);
102
+ uint256 v4Balance = v4Store.tierBalanceOf({hook: v4HookAddress, owner: owner, tierId: tierId});
103
+ uint256 v5Balance = v5Store.tierBalanceOf({hook: hookAddress, owner: owner, tierId: tierId});
102
104
 
103
105
  // Require that V5 balance is never greater than V4 balance
104
106
  require(
@@ -146,6 +148,7 @@ library MigrationHelper {
146
148
  bytes memory buffer = new bytes(digits);
147
149
  while (value != 0) {
148
150
  digits -= 1;
151
+ // forge-lint: disable-next-line(unsafe-typecast)
149
152
  buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
150
153
  value /= 10;
151
154
  }
@@ -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";
@@ -108,10 +108,15 @@ contract Banny721TokenUriResolver is
108
108
  /// @custom:param upc The universal product code that the SVG hash represent.
109
109
  mapping(uint256 upc => bytes32) public override svgHashOf;
110
110
 
111
+ // forge-lint: disable-next-line(mixed-case-variable)
111
112
  string public override DEFAULT_ALIEN_EYES;
113
+ // forge-lint: disable-next-line(mixed-case-variable)
112
114
  string public override DEFAULT_MOUTH;
115
+ // forge-lint: disable-next-line(mixed-case-variable)
113
116
  string public override DEFAULT_NECKLACE;
117
+ // forge-lint: disable-next-line(mixed-case-variable)
114
118
  string public override DEFAULT_STANDARD_EYES;
119
+ // forge-lint: disable-next-line(mixed-case-variable)
115
120
  string public override BANNY_BODY;
116
121
 
117
122
  //*********************************************************************//
@@ -299,7 +304,7 @@ contract Banny721TokenUriResolver is
299
304
 
300
305
  // Get a reference to the pricing context.
301
306
  // slither-disable-next-line unused-return
302
- (uint256 currency, uint256 decimals,) = IJB721TiersHook(hook).pricingContext();
307
+ (uint256 currency, uint256 decimals) = IJB721TiersHook(hook).pricingContext();
303
308
 
304
309
  attributes = string.concat(
305
310
  attributes,
@@ -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, jbPrices, jbRulesets, store, jbSplits, trustedForwarder);
1836
1828
 
1837
1829
  hookDeployer = new JB721TiersHookDeployer(hookImpl, store, addressRegistry, trustedForwarder);
1838
1830
  }
@@ -1908,9 +1900,7 @@ contract BannyForkTest is Test {
1908
1900
  baseUri: "ipfs://",
1909
1901
  tokenUriResolver: IJB721TokenUriResolver(address(resolver)),
1910
1902
  contractUri: "",
1911
- tiersConfig: JB721InitTiersConfig({
1912
- tiers: tiers, currency: JBCurrencyIds.ETH, decimals: 18, prices: IJBPrices(address(0))
1913
- }),
1903
+ tiersConfig: JB721InitTiersConfig({tiers: tiers, currency: JBCurrencyIds.ETH, decimals: 18}),
1914
1904
  reserveBeneficiary: address(0),
1915
1905
  flags: JB721TiersHookFlags({
1916
1906
  noNewTiersWithReserves: false,
@@ -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;