@bananapus/omnichain-deployers-v6 0.0.56 → 0.0.58

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/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  `@bananapus/omnichain-deployers-v6` launches Juicebox projects with cross-chain suckers and a 721 hook already wired in. It is the package you use when the default project shape should be omnichain from day one.
4
4
 
5
-
6
5
  ## Documentation
7
6
 
8
7
  - [INVARIANTS.md](./INVARIANTS.md) — runtime guarantees enforced by `JBOmnichainDeployer`, per-function caller / effect / invariant inventory, and cross-cutting invariants.
@@ -29,13 +28,13 @@ The wrapper exists so sucker-triggered flows can be exempted from project-specif
29
28
 
30
29
  Use this repo when the default project shape is "Juicebox project plus 721 hook plus cross-chain bridge." Do not use it when a project is single-chain or does not need the wrapper semantics around suckers.
31
30
 
32
- ## Key Contract
31
+ ## Key contract
33
32
 
34
33
  | Contract | Role |
35
34
  | --- | --- |
36
35
  | `JBOmnichainDeployer` | Launches projects and rulesets, manages per-ruleset hook composition, and deploys suckers with deterministic salts. |
37
36
 
38
- ## Mental Model
37
+ ## Mental model
39
38
 
40
39
  This repo owns orchestration plus runtime wrapping:
41
40
 
@@ -43,21 +42,21 @@ This repo owns orchestration plus runtime wrapping:
43
42
  2. remember which hook composition belongs to which ruleset
44
43
  3. special-case sucker behavior so bridge flows are not broken by project-specific logic
45
44
 
46
- ## Read These Files First
45
+ ## Read these files first
47
46
 
48
47
  1. `src/JBOmnichainDeployer.sol`
49
48
  2. `nana-suckers-v6/src/JBSucker.sol`
50
49
  3. `nana-721-hook-v6/src/JB721TiersHook.sol`
51
50
  4. the extra hook repo, if the deployment composes one
52
51
 
53
- ## Integration Traps
52
+ ## Integration traps
54
53
 
55
54
  - this repo wraps hooks and bridge flows together, so ownership and hook-order assumptions matter as much as deployment salt
56
55
  - ruleset ID prediction is a real implementation dependency
57
56
  - the deployer can carry forward an existing 721 hook shape, so stale hook assumptions can leak across deployments
58
57
  - bridge-safe wrapper behavior is part of the runtime trust model
59
58
 
60
- ## Where State Lives
59
+ ## Where state lives
61
60
 
62
61
  - orchestration and wrapper logic: `JBOmnichainDeployer`
63
62
  - bridge runtime state: `nana-suckers-v6`
@@ -83,11 +82,11 @@ Useful scripts:
83
82
  - `npm run deploy:mainnets`
84
83
  - `npm run deploy:testnets`
85
84
 
86
- ## Deployment Notes
85
+ ## Deployment notes
87
86
 
88
87
  This repo assumes the 721 hook, address registry, buyback hook, suckers, ownable, and core packages are already available. Matching salts from the same sender keep sucker addresses deterministic across chains.
89
88
 
90
- ## Repository Layout
89
+ ## Repository layout
91
90
 
92
91
  ```text
93
92
  src/
@@ -101,14 +100,14 @@ script/
101
100
  helpers/
102
101
  ```
103
102
 
104
- ## Risks And Notes
103
+ ## Risks and notes
105
104
 
106
105
  - ruleset ID prediction is part of the implementation strategy
107
106
  - hook composition order matters because the 721 hook runs before any extra custom hook
108
107
  - default empty-tier 721 config is convenient, but teams should still decide explicitly whether the hook participates in cash-out behavior
109
108
  - deterministic salts only help with cross-chain address alignment when sender and configuration match exactly
110
109
 
111
- ## For AI Agents
110
+ ## For AI agents
112
111
 
113
112
  - Describe this repo as an orchestration and wrapper layer, not as the source of sucker or 721 runtime behavior.
114
113
  - Start with `JBOmnichainDeployer`, then inspect the sibling repo that owns the behavior being questioned.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/omnichain-deployers-v6",
3
- "version": "0.0.56",
3
+ "version": "0.0.58",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "@bananapus/core-v6": "^0.0.78",
29
29
  "@bananapus/ownable-v6": "^0.0.34",
30
30
  "@bananapus/permission-ids-v6": "^0.0.28",
31
- "@bananapus/suckers-v6": "^0.0.67",
31
+ "@bananapus/suckers-v6": "^0.0.69",
32
32
  "@openzeppelin/contracts": "5.6.1"
33
33
  },
34
34
  "devDependencies": {
@@ -1,19 +1,19 @@
1
1
  # Omnichain Deployer Operations
2
2
 
3
- ## Deployment Surface
3
+ ## Deployment surface
4
4
 
5
5
  - [`src/JBOmnichainDeployer.sol`](../src/JBOmnichainDeployer.sol) is the first stop for launch, queue, and sucker-deployment behavior.
6
6
  - [`script/Deploy.s.sol`](../script/Deploy.s.sol) is the deployment entry point when the question is about current wiring rather than wrapper semantics.
7
7
  - [`src/structs/`](../src/structs/) defines the deploy and queue config types that often drift from memory.
8
8
 
9
- ## Change Checklist
9
+ ## Change checklist
10
10
 
11
11
  - If you edit launch or queue behavior, verify ruleset IDs, carry-forward behavior, and stored hook config keys together.
12
12
  - If you edit salt handling, confirm deterministic-address assumptions for both suckers and 721 hooks.
13
13
  - If you edit wrapper behavior, check both pay and cash-out paths, not only one.
14
14
  - If you touch mint-permission logic, confirm whether the permission should come from suckers, the extra hook, or neither.
15
15
 
16
- ## Common Failure Modes
16
+ ## Common failure modes
17
17
 
18
18
  - Wrapper behavior is blamed on the composed hook, but the deployer stored the wrong hook config for the ruleset.
19
19
  - A same-block queue assumption breaks predicted ruleset IDs and silently strands stored config.
@@ -21,7 +21,7 @@
21
21
  - Deterministic deployment assumptions fail because sender or salt composition changed.
22
22
  - Existing-project sucker deployment is treated as a pure `DEPLOY_SUCKERS` flow even though the registry also performs token mapping, so missing `MAP_SUCKER_TOKEN` authority for the registry shows up only when the deploy path reaches `mapTokens`.
23
23
 
24
- ## Useful Proof Points
24
+ ## Useful proof points
25
25
 
26
26
  - [`test/JBOmnichainDeployer.t.sol`](../test/JBOmnichainDeployer.t.sol) for baseline deploy and queue flows.
27
27
  - [`test/TestRegressionGaps.sol`](../test/TestRegressionGaps.sol) for pinned edge cases.
@@ -1,10 +1,10 @@
1
1
  # Omnichain Deployer Runtime
2
2
 
3
- ## Contract Role
3
+ ## Contract role
4
4
 
5
5
  - [`src/JBOmnichainDeployer.sol`](../src/JBOmnichainDeployer.sol) launches projects, deploys suckers, installs a 721 hook, wraps extra hooks, and serves as the live ruleset data-hook wrapper for the projects it creates.
6
6
 
7
- ## Runtime Path
7
+ ## Runtime path
8
8
 
9
9
  1. Project launch or ruleset queue stores the relevant 721 hook and optional extra hook per ruleset.
10
10
  2. The deployer installs itself as the data-hook wrapper on the ruleset.
@@ -12,7 +12,7 @@
12
12
  4. On cash out, it can short-circuit for suckers, otherwise it forwards into the configured hook stack in order.
13
13
  5. Mint permission queries can be granted by suckers or by the configured extra hook.
14
14
 
15
- ## High-Risk Areas
15
+ ## High-risk areas
16
16
 
17
17
  - Ruleset ID prediction: if the predicted ID is wrong, hook config can be stored under the wrong key.
18
18
  - Hook composition order: 721 logic runs before any extra hook, which affects both specs and accounting.
@@ -20,7 +20,7 @@
20
20
  - Carry-forward logic: queueing rulesets without new tiers intentionally reuses the latest 721 hook.
21
21
  - Meta-transaction sender handling: salt derivation uses `_msgSender()`, not raw `msg.sender`.
22
22
 
23
- ## Tests To Trust First
23
+ ## Tests to trust first
24
24
 
25
25
  - [`test/Tiered721HookComposition.t.sol`](../test/Tiered721HookComposition.t.sol) for hook-composition behavior.
26
26
  - [`test/JBOmnichainDeployerGuard.t.sol`](../test/JBOmnichainDeployerGuard.t.sol) and [`test/OmnichainDeployerAttacks.t.sol`](../test/OmnichainDeployerAttacks.t.sol) for safety properties.
@@ -22,6 +22,7 @@ import {JBOwnable} from "@bananapus/ownable-v6/src/JBOwnable.sol";
22
22
  import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
23
23
  import {IJBPeerChainAdjustedAccounts} from "@bananapus/suckers-v6/src/interfaces/IJBPeerChainAdjustedAccounts.sol";
24
24
  import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
25
+ import {JBSourceContext} from "@bananapus/suckers-v6/src/structs/JBSourceContext.sol";
25
26
  import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
26
27
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
27
28
  import {Context} from "@openzeppelin/contracts/utils/Context.sol";
@@ -157,6 +158,7 @@ contract JBOmnichainDeployer is
157
158
  /// call on both chains for deterministic address matching.
158
159
  /// @param projectId The ID of the project to deploy suckers for.
159
160
  /// @param suckerDeploymentConfiguration The suckers to set up for the project.
161
+ /// @return suckers The addresses of the deployed suckers.
160
162
  function deploySuckersFor(
161
163
  uint256 projectId,
162
164
  JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration
@@ -434,7 +436,7 @@ contract JBOmnichainDeployer is
434
436
  // If the ruleset aggregates cross-chain state, add remote supply and surplus.
435
437
  if (!context.scopeCashOutsToLocalBalances) {
436
438
  totalSupply += SUCKER_REGISTRY.remoteTotalSupplyOf(context.projectId);
437
- effectiveSurplusValue += SUCKER_REGISTRY.remoteSurplusOf({
439
+ effectiveSurplusValue += SUCKER_REGISTRY.totalRemoteSurplusOf({
438
440
  projectId: context.projectId,
439
441
  decimals: context.surplus.decimals,
440
442
  currency: uint256(context.surplus.currency)
@@ -682,44 +684,38 @@ contract JBOmnichainDeployer is
682
684
  }
683
685
 
684
686
  /// @notice Forwards peer-chain adjusted accounts from the stored extra data hook. Suckers call this on the active
685
- /// data hook (which is this deployer after wrapping) to learn about additional supply/surplus/balance that should
686
- /// be included in cross-chain snapshots. Without forwarding, the extra hook's peer-chain adjustments are silently
687
- /// masked, causing the bonding curve to use only local values and over-reclaiming on peer chains.
687
+ /// data hook (which is this deployer after wrapping) to learn about additional supply and per-context surplus and
688
+ /// balance that should be included in cross-chain snapshots. Without forwarding, the extra hook's peer-chain
689
+ /// adjustments are silently masked, causing the bonding curve to use only local values and over-reclaiming on peer
690
+ /// chains.
688
691
  /// @dev Part of `IJBPeerChainAdjustedAccounts`. Uses staticcall to safely handle extra hooks that do not implement
689
692
  /// this interface.
690
693
  /// @param projectId The ID of the project to snapshot.
691
- /// @param decimals The decimals the returned surplus and balance should use.
692
- /// @param currency The currency the returned surplus and balance should be in terms of.
693
694
  /// @return supply The extra supply to include in `sourceTotalSupply`.
694
- /// @return surplus The extra surplus to include in `sourceSurplus`.
695
- /// @return balance The extra balance to include in `sourceBalance`.
696
- function peerChainAdjustedAccountsOf(
697
- uint256 projectId,
698
- uint256 decimals,
699
- uint256 currency
700
- )
695
+ /// @return contexts The extra per-context surplus and balance to include in the snapshot, un-valued.
696
+ function peerChainAdjustedAccountsOf(uint256 projectId)
701
697
  external
702
698
  view
703
699
  override
704
- returns (uint256 supply, uint256 surplus, uint256 balance)
700
+ returns (uint256 supply, JBSourceContext[] memory contexts)
705
701
  {
706
702
  // Get the current ruleset from the canonical controller to look up the stored extra hook.
707
703
  (JBRuleset memory ruleset,) = CONTROLLER.currentRulesetOf(projectId);
708
704
 
709
705
  // Look up the extra data hook for this project's current ruleset.
710
706
  JBDeployerHookConfig memory extraHook = _extraDataHookOf[projectId][ruleset.id];
711
- if (address(extraHook.dataHook) == address(0)) return (0, 0, 0);
707
+ if (address(extraHook.dataHook) == address(0)) return (0, new JBSourceContext[](0));
712
708
 
713
709
  // Forward via staticcall — the extra hook may or may not implement IJBPeerChainAdjustedAccounts.
714
710
  (bool success, bytes memory data) = address(extraHook.dataHook)
715
- .staticcall(
716
- abi.encodeCall(
717
- IJBPeerChainAdjustedAccounts.peerChainAdjustedAccountsOf, (projectId, decimals, currency)
718
- )
719
- );
720
- if (!success || data.length < 96) return (0, 0, 0);
721
-
722
- return abi.decode(data, (uint256, uint256, uint256));
711
+ .staticcall(abi.encodeCall(IJBPeerChainAdjustedAccounts.peerChainAdjustedAccountsOf, (projectId)));
712
+
713
+ // A well-formed `(uint256, JBSourceContext[])` return is at least three words: the supply, the array offset,
714
+ // and the array length. Anything shorter (an empty return, a hook with no code, or a mismatched ABI) is
715
+ // treated as no contribution rather than letting the decode revert.
716
+ if (!success || data.length < 96) return (0, new JBSourceContext[](0));
717
+
718
+ return abi.decode(data, (uint256, JBSourceContext[]));
723
719
  }
724
720
 
725
721
  //*********************************************************************//
@@ -765,6 +761,9 @@ contract JBOmnichainDeployer is
765
761
  }
766
762
 
767
763
  /// @notice Internal implementation of `launchProjectFor`.
764
+ /// @return projectId The ID of the newly launched project.
765
+ /// @return hook The 721 tiers hook that was deployed for the project.
766
+ /// @return suckers The addresses of the deployed suckers.
768
767
  function _launchProjectFor(
769
768
  address owner,
770
769
  string calldata projectUri,
@@ -828,6 +827,8 @@ contract JBOmnichainDeployer is
828
827
  }
829
828
 
830
829
  /// @notice Internal implementation of `launchRulesetsFor`.
830
+ /// @return rulesetId The ID of the newly launched rulesets.
831
+ /// @return hook The 721 tiers hook that was deployed for the project.
831
832
  function _launchRulesetsFor(
832
833
  uint256 projectId,
833
834
  string calldata projectUri,
@@ -880,6 +881,8 @@ contract JBOmnichainDeployer is
880
881
  }
881
882
 
882
883
  /// @notice Internal implementation of `queueRulesetsOf`.
884
+ /// @return rulesetId The ID of the newly queued rulesets.
885
+ /// @return hook The 721 tiers hook (newly deployed or carried forward from the previous ruleset).
883
886
  function _queueRulesetsOf(
884
887
  uint256 projectId,
885
888
  JBOmnichain721Config memory deploy721Config,
@@ -924,7 +927,8 @@ contract JBOmnichainDeployer is
924
927
  // (or has no approval hook), its hook config should take precedence.
925
928
  // Conservative: only use Approved or Empty status. ApprovalExpected is intentionally
926
929
  // excluded because hook selection is irreversible — if the pending ruleset is later rejected
927
- // by the approval hook, we'd have locked in a hook from a ruleset that never became active.
930
+ // by the approval hook, the deployer would otherwise lock in a hook from a ruleset that never
931
+ // became active.
928
932
  (JBRuleset memory latestQueued, JBApprovalStatus approvalStatus) =
929
933
  CONTROLLER.RULESETS().latestQueuedOf(projectId);
930
934
  if (
@@ -13,6 +13,7 @@ import {JBSuckerDeploymentConfig} from "../structs/JBSuckerDeploymentConfig.sol"
13
13
  /// pay/cash-out logic through a data hook wrapper.
14
14
  interface IJBOmnichainDeployer {
15
15
  /// @notice The controller used for every project launch and ruleset queue.
16
+ /// @return controller The controller used for every project launch and ruleset queue.
16
17
  function CONTROLLER() external view returns (IJBController);
17
18
 
18
19
  /// @notice Get the extra data hook for a project and ruleset.
@@ -5,9 +5,9 @@ import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDa
5
5
 
6
6
  /// @notice Configuration for an extra data hook (e.g. a buyback hook) that the omnichain deployer delegates to
7
7
  /// alongside the primary 721 hook. Stored per project per ruleset.
8
- /// @param dataHook The extra data hook contract to delegate to.
9
- /// @param useDataHookForPay Whether to call this hook's `beforePayRecordedWith` during payments.
10
- /// @param useDataHookForCashOut Whether to call this hook's `beforeCashOutRecordedWith` during cash outs.
8
+ /// @custom:member dataHook The extra data hook contract to delegate to.
9
+ /// @custom:member useDataHookForPay Whether to call this hook's `beforePayRecordedWith` during payments.
10
+ /// @custom:member useDataHookForCashOut Whether to call this hook's `beforeCashOutRecordedWith` during cash outs.
11
11
  struct JBDeployerHookConfig {
12
12
  IJBRulesetDataHook dataHook;
13
13
  bool useDataHookForPay;
@@ -4,10 +4,10 @@ pragma solidity ^0.8.0;
4
4
  import {JBDeploy721TiersHookConfig} from "@bananapus/721-hook-v6/src/structs/JBDeploy721TiersHookConfig.sol";
5
5
 
6
6
  /// @notice Configuration for deploying a 721 tiers hook alongside omnichain rulesets.
7
- /// @param deployTiersHookConfig Configuration which dictates the behavior of the 721 tiers hook to deploy.
8
- /// @param useDataHookForCashOut Whether the 721 hook should handle cash outs (via beforeCashOutRecordedWith).
9
- /// @param salt A salt to use for the deterministic 721 hook deployment. Combined with `msg.sender` internally, so
10
- /// cross-chain deterministic addresses require the same sender on each chain.
7
+ /// @custom:member deployTiersHookConfig Configuration which dictates the behavior of the 721 tiers hook to deploy.
8
+ /// @custom:member useDataHookForCashOut Whether the 721 hook should handle cash outs (via beforeCashOutRecordedWith).
9
+ /// @custom:member salt A salt to use for the deterministic 721 hook deployment. Combined with `msg.sender` internally,
10
+ /// so cross-chain deterministic addresses require the same sender on each chain.
11
11
  struct JBOmnichain721Config {
12
12
  JBDeploy721TiersHookConfig deployTiersHookConfig;
13
13
  bool useDataHookForCashOut;
@@ -3,6 +3,8 @@ pragma solidity ^0.8.0;
3
3
 
4
4
  import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
5
5
 
6
+ /// @notice Configuration for deploying a project's suckers in one call: the per-peer deployer configs plus the salt
7
+ /// that seeds deterministic addresses.
6
8
  /// @custom:member deployerConfigurations Sucker deployer configs and token mappings for peer chains.
7
9
  /// @custom:member salt The salt combined with `_msgSender()` to create deterministic sucker addresses.
8
10
  struct JBSuckerDeploymentConfig {
@@ -4,8 +4,8 @@ pragma solidity ^0.8.0;
4
4
  import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
5
5
 
6
6
  /// @notice Stored configuration for a project's tiered 721 hook within a specific ruleset.
7
- /// @param hook The tiered 721 hook contract used for NFT minting on payments.
8
- /// @param useDataHookForCashOut Whether the 721 hook should participate in cash-out tax calculations and NFT
7
+ /// @custom:member hook The tiered 721 hook contract used for NFT minting on payments.
8
+ /// @custom:member useDataHookForCashOut Whether the 721 hook should participate in cash-out tax calculations and NFT
9
9
  /// redemptions.
10
10
  struct JBTiered721HookConfig {
11
11
  IJB721TiersHook hook;