@bananapus/omnichain-deployers-v6 0.0.19 → 0.0.21

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/ADMINISTRATION.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  Admin privileges and their scope in nana-omnichain-deployers-v6.
4
4
 
5
+ ## At A Glance
6
+
7
+ | Item | Details |
8
+ |------|---------|
9
+ | Scope | Omnichain project launch, hook composition, sucker deployment, and the deployer's data-hook proxy behavior. |
10
+ | Operators | Project owners and delegates, the `JBOmnichainDeployer`, and the configured `JBSuckerRegistry` with its wildcard token-mapping grant. |
11
+ | Highest-risk actions | Launching a project with the wrong hook composition, terminal configuration, or cross-chain setup, then assuming it can be rewritten later. |
12
+ | Recovery posture | The deployer's immutable dependencies cannot be edited in place. Project-level recovery usually means launching corrected rulesets or redeploying the broader project path. |
13
+
14
+ ## Routine Operations
15
+
16
+ - Validate all deploy-time hook choices, 721 settings, and sucker configuration before using `launchProjectFor` or `launchRulesetsFor`.
17
+ - Keep the distinction clear between per-ruleset composed hooks and the deployer's permanent proxy role.
18
+ - Use the deployer when you want its tax-free sucker and mint-permission behavior; otherwise, do not assume it is a drop-in replacement for arbitrary hook wiring.
19
+
20
+ ## One-Way Or High-Risk Actions
21
+
22
+ - Constructor-time wildcard permissions and immutable references on the deployer cannot be changed afterward.
23
+ - Launch-time hook composition choices determine how future pay and cash-out flows are merged for that ruleset.
24
+ - A bad omnichain deployment can leave a project with a cross-chain shape that is expensive to unwind operationally.
25
+
26
+ ## Recovery Notes
27
+
28
+ - If the project is still administratively flexible, queue new rulesets or use project-level migration paths to move to corrected hook composition.
29
+ - If the deployer's own immutable assumptions are wrong, recovery means deploying a new deployer path rather than trying to hot-fix the existing one.
30
+
5
31
  ## Roles
6
32
 
7
33
  | Role | How Assigned | Scope |
@@ -17,7 +43,7 @@ Admin privileges and their scope in nana-omnichain-deployers-v6.
17
43
 
18
44
  | Function | Required Role | Permission ID | Scope | What It Does |
19
45
  |----------|--------------|---------------|-------|--------------|
20
- | `deploySuckersFor` | Project owner or operator | `DEPLOY_SUCKERS` | Per-project | Deploys new cross-chain suckers for an existing project via the sucker registry. |
46
+ | `deploySuckersFor` | Project owner or operator | `DEPLOY_SUCKERS` | Per-project | Deploys new cross-chain suckers for an existing project via the sucker registry. The same operation also applies token mappings on the new suckers, so existing projects must already have the registry arranged as an authorized `MAP_SUCKER_TOKEN` operator for that project. |
21
47
  | `launchRulesetsFor` | Project owner or operator | `LAUNCH_RULESETS` + `SET_TERMINALS` | Per-project | Deploys a 721 tiers hook, launches new rulesets with terminal configuration for an existing project. Has a simplified overload without `deploy721Config`. |
22
48
  | `queueRulesetsOf` | Project owner or operator | `QUEUE_RULESETS` | Per-project | Queues new rulesets for an existing project. If tiers provided, deploys a new 721 hook. Otherwise, carries forward the 721 hook from the latest ruleset. Has a simplified overload without `deploy721Config`. |
23
49
 
@@ -55,12 +81,14 @@ Admin privileges and their scope in nana-omnichain-deployers-v6.
55
81
 
56
82
  | Action | Who | Mechanism |
57
83
  |--------|-----|-----------|
58
- | Deploy suckers for existing project | Project owner or DEPLOY_SUCKERS operator | `deploySuckersFor` calls `SUCKER_REGISTRY.deploySuckersFor` |
84
+ | Deploy suckers for existing project | Project owner or DEPLOY_SUCKERS operator | `deploySuckersFor` calls `SUCKER_REGISTRY.deploySuckersFor`; because the registry also applies the initial mappings, existing projects must pair this with a project-level `MAP_SUCKER_TOKEN` arrangement for the registry |
59
85
  | Deploy suckers during project launch | Project deployer (anyone) | Included in `launchProjectFor` if `salt != bytes32(0)` |
60
86
  | Map sucker tokens | JBSuckerRegistry | Granted MAP_SUCKER_TOKEN at construction with projectId=0 wildcard |
61
87
  | Grant 0% cash-out tax to suckers | Automatic | `beforeCashOutRecordedWith` checks `SUCKER_REGISTRY.isSuckerOf` |
62
88
  | Grant mint permission to suckers | Automatic | `hasMintPermissionFor` checks `SUCKER_REGISTRY.isSuckerOf` |
63
89
 
90
+ **Existing-project operator note:** `deploySuckersFor` looks like a deployment-only action at the top level, but it is intentionally a deploy-and-map flow. If an existing project delegates `DEPLOY_SUCKERS` without also arranging `MAP_SUCKER_TOKEN` for the registry, the transaction will fail once the registry reaches the mapping step.
91
+
64
92
  **Cross-chain determinism:** The salt for sucker deployment is combined with `_msgSender()` (`keccak256(abi.encode(salt, _msgSender()))`). Deploying from the same sender address with the same salt on each chain produces matching sucker addresses.
65
93
 
66
94
  ## Data Hook Proxy Pattern
package/ARCHITECTURE.md CHANGED
@@ -1,107 +1,70 @@
1
- # nana-omnichain-deployers-v6 — Architecture
1
+ # Architecture
2
2
 
3
3
  ## Purpose
4
4
 
5
- Omnichain project deployer for Juicebox V6. Wraps the project deployment flow to automatically configure cross-chain suckers and a 721 tiers hook, acting as a data hook that gives suckers 0% cash-out tax (bridging privilege) and mint permission. Every project gets a 721 hook (even with 0 initial tiers).
5
+ `nana-omnichain-deployers-v6` launches Juicebox projects that are ready for both tiered NFTs and cross-chain suckers from day one. It also acts as a wrapper data hook so it can compose a 721 hook with an optional extra data hook while granting suckers tax-free cash outs and mint permission.
6
6
 
7
- ## Contract Map
7
+ ## Boundaries
8
8
 
9
- ```
10
- src/
11
- ├── JBOmnichainDeployer.sol — Deploys projects with sucker + 721 hook integration, acts as data hook wrapper
12
- ├── interfaces/
13
- │ └── IJBOmnichainDeployer.sol — Interface
14
- └── structs/
15
- ├── JBDeployerHookConfig.sol — Custom hook configuration for deployment
16
- ├── JBOmnichain721Config.sol — 721 hook deployment config (tiers + cashout flag + salt)
17
- ├── JBTiered721HookConfig.sol — Per-ruleset 721 hook configuration
18
- └── JBSuckerDeploymentConfig.sol — Sucker deployment parameters
19
- ```
20
-
21
- ## Hook Storage Mappings
9
+ - `JBOmnichainDeployer` is both a deployer and a live hook wrapper. Those two roles are inseparable.
10
+ - The repo composes `nana-721-hook-v6` and `nana-suckers-v6`; it should not duplicate their internal logic.
11
+ - Project accounting still happens in the core protocol.
22
12
 
23
- The deployer maintains two internal mappings, both keyed by `(projectId, rulesetId)`:
13
+ ## Main Components
24
14
 
25
- - **`_tiered721HookOf`** Stores the project's `IJB721TiersHook` reference and a `useDataHookForCashOut` flag. Always populated for every ruleset (every project gets a 721 hook). The hook is always consulted for payments (it controls NFT tier minting), and optionally consulted for cash outs based on the flag.
15
+ | Component | Responsibility |
16
+ | --- | --- |
17
+ | `JBOmnichainDeployer` | Project launch, ruleset queueing, hook composition, and sucker-safe cash-out policy |
18
+ | config structs | 721 hook config, extra hook config, and sucker deployment config |
19
+ | `IJBOmnichainDeployer` | Public deployer and inspection interface |
26
20
 
27
- - **`_extraDataHookOf`** — Stores an optional secondary data hook (e.g., a buyback hook) extracted from the ruleset's original `metadata.dataHook` field before the deployer overwrites it with itself. Includes separate `useDataHookForPay` and `useDataHookForCashOut` flags, preserved from the original ruleset metadata. Only populated when the caller's ruleset config specifies a non-zero `dataHook`.
21
+ ## Runtime Model
28
22
 
29
- During `_setup721`, the deployer extracts any user-specified data hook into `_extraDataHookOf`, then replaces `metadata.dataHook` with itself and forces both pay/cashout flags to `true`. At runtime, the deployer delegates to the 721 hook first, then the extra hook (if present), and merges their results.
23
+ ### Launch
30
24
 
31
- ## Key Data Flows
32
-
33
- ### Omnichain Project Deployment
34
- ```
35
- Caller JBOmnichainDeployer.launchProjectFor()
36
- Deploy 721 hook via HOOK_DEPLOYER (always, even with 0 tiers)
37
- _setup721(): store hooks, insert deployer as data hook
38
- → Launch JB project via controller.launchProjectFor
39
- → Transfer 721 hook ownership to project (after project NFT exists)
40
- → Deploy suckers via JBSuckerRegistry
41
- → Transfer project NFT to owner
25
+ ```text
26
+ caller
27
+ -> launch project or queue rulesets through the deployer
28
+ -> deployer installs itself as the ruleset data hook
29
+ -> deployer deploys or carries forward the 721 hook
30
+ -> deployer optionally deploys sucker pairs with deterministic salts
31
+ -> project ownership is transferred to the intended owner
42
32
  ```
43
33
 
44
- ### Data Hook Behavior
45
- ```
46
- Payment → JBOmnichainDeployer.beforePayRecordedWith()
47
- → Calls 721 hook first (from _tiered721HookOf) for specs/split amounts
48
- → If 721 hook returned specs: include in merged output
49
- → Calls custom hook from _extraDataHookOf (if useDataHookForPay=true)
50
- → Custom hook receives reduced amount (payment - splitAmount)
51
- → Uses 721 hook's split-adjusted weight directly
52
- → Merges both hook specs (721 first if any, then custom)
53
-
54
- Cash Out → JBOmnichainDeployer.beforeCashOutRecordedWith()
55
- → If caller is a registered sucker: return 0% cash-out tax (early return)
56
- → Calls 721 hook (from _tiered721HookOf, if useDataHookForCashOut=true)
57
- → Updates cashOutTaxRate, cashOutCount, totalSupply from 721 hook response
58
- → Calls custom hook (from _extraDataHookOf, if useDataHookForCashOut=true)
59
- → Receives already-updated values from 721 hook
60
- → Further updates cashOutTaxRate, cashOutCount, totalSupply
61
- → Merges both hooks' specifications (721 specs first, then custom hook specs)
62
- → If 721 hook has flag=true and reverts (fungible cashout): revert propagates
63
- → If neither hook has the flag set: return original values
64
- ```
34
+ ### Pay And Cash-Out Wrapping
65
35
 
66
- ### Ruleset Management
67
- ```
68
- Owner JBOmnichainDeployer.queueRulesetsOf()
69
- If new tiers provided: deploy new 721 hook
70
- If no new tiers: carry forward 721 hook from latest ruleset
71
- _setup721(): store hooks, insert deployer as data hook
72
- → Queue new rulesets via JBController
73
-
74
- Owner → JBOmnichainDeployer.launchRulesetsFor()
75
- → Deploy new 721 hook
76
- → Launch rulesets for an existing project
77
- → Configure terminal integration
36
+ ```text
37
+ runtime callback
38
+ -> if the actor is a registered sucker, return the special tax-free / mint-enabled path
39
+ -> otherwise call the 721 hook first when configured
40
+ -> then call the extra data hook when configured
41
+ -> merge hook specs in order and return the combined result
78
42
  ```
79
43
 
80
- ## Extension Points
81
-
82
- | Point | Interface | Purpose |
83
- |-------|-----------|---------|
84
- | Data hook (pay) | `IJBRulesetDataHook.beforePayRecordedWith` | Compose 721 + custom hook for payments |
85
- | Data hook (cashout) | `IJBRulesetDataHook.beforeCashOutRecordedWith` | 0% tax for suckers, forward to hooks |
86
- | Sucker registry | `IJBSuckerRegistry` | Sucker deployment and discovery |
87
- | 721 hook deployer | `IJB721TiersHookDeployer` | 721 tiers hook deployment (always used) |
44
+ ## Critical Invariants
88
45
 
89
- ## Design Decisions
46
+ - Suckers must be able to bridge without getting trapped behind custom cash-out policies.
47
+ - Hook order matters: the 721 hook runs first, and the extra hook receives the updated context.
48
+ - The deployer's predicted ruleset IDs must stay aligned with `JBRulesets` behavior; the storage keys depend on it.
49
+ - Every project launched through this repo gets a 721 hook surface, even if it starts with zero tiers.
90
50
 
91
- 1. **Always deploy a 721 hook, even with 0 tiers.** Every project gets a 721 hook instance so that NFT tiers can be added later via `queueRulesetsOf` without changing the data hook architecture. The hook is also needed as the pay hook target for tier minting. Deploying with 0 tiers is a no-op at runtime (no specs returned) but keeps the infrastructure in place.
51
+ ## Where Complexity Lives
92
52
 
93
- 2. **Deployer acts as a data hook wrapper instead of direct hook assignment.** The core protocol only supports a single `dataHook` per ruleset. The deployer inserts itself as that hook so it can compose two hooks (721 + custom) behind a single interface, while also injecting sucker-specific logic (0% cash-out tax for suckers, mint permission for suckers). Without this wrapper, projects would have to choose between NFT tiers, a buyback hook, and sucker privileges.
53
+ - This repo hides composition complexity behind a simple launch surface, which makes stale assumptions dangerous.
54
+ - Ruleset ID prediction is a subtle but central storage keying mechanism.
55
+ - The sucker exception path intentionally short-circuits normal hook composition and must stay easy to reason about.
94
56
 
95
- 3. **721 hook specs are merged first, custom hook specs second.** During payments, the 721 hook's split amount is subtracted from the payment before the custom hook sees it. This ordering ensures the 721 hook claims funds for tier mints at full price, and the custom hook (e.g., buyback) operates on the remaining amount. For cash outs, the 721 hook adjusts `cashOutTaxRate`/`cashOutCount`/`totalSupply` first, and the custom hook receives those already-updated values, allowing each hook to build on the previous hook's adjustments.
57
+ ## Dependencies
96
58
 
97
- 4. **721 hook's weight is used directly after tier splits.** The 721 hook's `beforePayRecordedWith` returns a weight that is already adjusted for tier-split deductions (via `JB721TiersHookLib.calculateWeight`). The deployer uses this weight directly instead of re-scaling with `mulDiv`. This prevents double-counting: the 721 hook mints its own NFTs for the split amount, and the terminal mints fungible tokens only for the remainder at the hook's pre-adjusted weight.
59
+ - `nana-core-v6` for project launch and hook interfaces
60
+ - `nana-721-hook-v6` for tiered NFT behavior
61
+ - `nana-suckers-v6` for cross-chain transport
62
+ - `nana-ownable-v6` for project-following hook ownership
98
63
 
99
- 5. **Ruleset IDs are predicted as `block.timestamp + i`.** The deployer must store hook configs keyed by ruleset ID before the rulesets are actually created. It predicts IDs using the core protocol's convention (`block.timestamp` for the first, incrementing for subsequent rulesets in the same transaction). `queueRulesetsOf` explicitly reverts if `latestRulesetId >= block.timestamp`, which would mean rulesets were already queued in the same block and the prediction would be wrong.
64
+ ## Safe Change Guide
100
65
 
101
- ## Dependencies
102
- - `@bananapus/core-v6` Core protocol (controller, directory, permissions)
103
- - `@bananapus/721-hook-v6` NFT tier deployment
104
- - `@bananapus/ownable-v6` JB-aware ownership
105
- - `@bananapus/permission-ids-v6` Permission constants
106
- - `@bananapus/suckers-v6` — Cross-chain sucker registry
107
- - `@openzeppelin/contracts` — ERC2771, ERC721Receiver
66
+ - Review launch-time logic and runtime-hook logic together. This repo is easy to break by fixing only one side.
67
+ - When changing hook composition, verify both payment and cash-out ordering.
68
+ - If you touch ruleset ID prediction, test same-block and queued-ruleset edge cases explicitly.
69
+ - Keep deterministic salt handling stable across chains; address predictability is part of the feature.
70
+ - Treat "transparent wrapper" claims as something to prove continuously, not assume.