@bananapus/omnichain-deployers-v6 0.0.31 → 0.0.35
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/CHANGELOG.md +1 -1
- package/README.md +2 -2
- package/foundry.toml +2 -1
- package/package.json +20 -11
- package/src/JBOmnichainDeployer.sol +72 -37
- package/src/interfaces/IJBOmnichainDeployer.sol +8 -1
- package/src/structs/JBDeployerHookConfig.sol +5 -0
- package/src/structs/JBTiered721HookConfig.sol +4 -0
- package/ADMINISTRATION.md +0 -29
- package/ARCHITECTURE.md +0 -31
- package/AUDIT_INSTRUCTIONS.md +0 -29
- package/RISKS.md +0 -97
- package/SKILLS.md +0 -25
- package/STYLE_GUIDE.md +0 -610
- package/USER_JOURNEYS.md +0 -63
- package/foundry.lock +0 -11
- package/slither-ci.config.json +0 -10
- package/sphinx.lock +0 -491
- package/test/JBOmnichainDeployer.t.sol +0 -639
- package/test/JBOmnichainDeployerGuard.t.sol +0 -404
- package/test/OmnichainDeployerAttacks.t.sol +0 -432
- package/test/OmnichainDeployerEdgeCases.t.sol +0 -827
- package/test/OmnichainDeployerReentrancy.t.sol +0 -321
- package/test/TestAuditGaps.sol +0 -996
- package/test/Tiered721HookComposition.t.sol +0 -909
- package/test/audit/AuditFixesC2H6M14.t.sol +0 -480
- package/test/audit/CarryForwardRejectedHook.t.sol +0 -328
- package/test/audit/CashOutCountPropagation.t.sol +0 -232
- package/test/audit/CashOutSpecMerge.t.sol +0 -372
- package/test/audit/DeterministicDrift.t.sol +0 -78
- package/test/audit/DeterministicPeerDrift.t.sol +0 -79
- package/test/audit/ExtraCashOutHookZeroReclaim.t.sol +0 -340
- package/test/audit/ForwardedPermissions.t.sol +0 -297
- package/test/audit/JBOmnichainDeployer.t.sol +0 -321
- package/test/audit/NftCashoutSupplyMismatch.t.sol +0 -224
- package/test/audit/OmnichainAudit.t.sol +0 -168
- package/test/audit/SplitCreditWeight.t.sol +0 -437
- package/test/audit/WeightScalingComparison.t.sol +0 -350
- package/test/fork/OmnichainForkTestBase.sol +0 -535
- package/test/fork/TestOmnichain721QueueAndAdjust.t.sol +0 -252
- package/test/fork/TestOmnichainCashOutFork.t.sol +0 -184
- package/test/fork/TestOmnichainStressFork.t.sol +0 -552
- package/test/fork/TestOmnichainWeightFork.t.sol +0 -60
- package/test/fork/TestSuckerDeploymentFork.t.sol +0 -229
- package/test/invariants/CrossChainDeployerInvariant.t.sol +0 -208
- package/test/invariants/OmnichainDeployerInvariant.t.sol +0 -150
- package/test/invariants/handlers/CrossChainDeployerHandler.sol +0 -394
- package/test/invariants/handlers/OmnichainDeployerHandler.sol +0 -262
- package/test/regression/EmptyRulesetConfigurations.t.sol +0 -84
- package/test/regression/HookOwnershipTransfer.t.sol +0 -152
- package/test/regression/ValidateController.t.sol +0 -169
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## v6
|
|
3
|
+
## v6 carry-forward hook fix
|
|
4
4
|
|
|
5
5
|
- **Carry-forward hook selection improved.** `queueRulesetsOf` now checks `latestQueuedOf(projectId)` before falling back to `currentOf(projectId)` when carrying forward a 721 hook. Previously it only read `currentOf`, which could miss a recently queued (and approved) ruleset's hook config. The source ruleset must have approval status `Approved` or `Empty` and a stored hook config in the deployer.
|
|
6
6
|
- The `useDataHookForCashOut` flag is preserved from whichever source ruleset is selected during carry-forward.
|
package/README.md
CHANGED
package/foundry.toml
CHANGED
|
@@ -15,7 +15,8 @@ depth = 100
|
|
|
15
15
|
fail_on_revert = false
|
|
16
16
|
|
|
17
17
|
[lint]
|
|
18
|
-
exclude_lints = ["
|
|
18
|
+
exclude_lints = ["mixed-case-variable", "pascal-case-struct"]
|
|
19
|
+
|
|
19
20
|
[fmt]
|
|
20
21
|
number_underscore = "thousands"
|
|
21
22
|
multiline_func_header = "all"
|
package/package.json
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bananapus/omnichain-deployers-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.35",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/Bananapus/nana-omnichain-deployers-v6"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"CHANGELOG.md",
|
|
11
|
+
"foundry.toml",
|
|
12
|
+
"references/",
|
|
13
|
+
"remappings.txt",
|
|
14
|
+
"script/Deploy.s.sol",
|
|
15
|
+
"script/helpers/",
|
|
16
|
+
"src/"
|
|
17
|
+
],
|
|
9
18
|
"engines": {
|
|
10
19
|
"node": ">=20.0.0"
|
|
11
20
|
},
|
|
@@ -17,17 +26,17 @@
|
|
|
17
26
|
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'nana-omnichain-deployers-v6'"
|
|
18
27
|
},
|
|
19
28
|
"dependencies": {
|
|
20
|
-
"@bananapus/721-hook-v6": "
|
|
21
|
-
"@bananapus/
|
|
22
|
-
"@bananapus/
|
|
23
|
-
"@bananapus/
|
|
24
|
-
"@bananapus/
|
|
25
|
-
"@
|
|
26
|
-
"@openzeppelin/contracts": "^5.6.1",
|
|
27
|
-
"@uniswap/v4-core": "^1.0.2"
|
|
29
|
+
"@bananapus/721-hook-v6": "0.0.43",
|
|
30
|
+
"@bananapus/core-v6": "0.0.39",
|
|
31
|
+
"@bananapus/ownable-v6": "0.0.24",
|
|
32
|
+
"@bananapus/permission-ids-v6": "0.0.22",
|
|
33
|
+
"@bananapus/suckers-v6": "0.0.32",
|
|
34
|
+
"@openzeppelin/contracts": "5.6.1"
|
|
28
35
|
},
|
|
29
36
|
"devDependencies": {
|
|
30
|
-
"@bananapus/address-registry-v6": "
|
|
31
|
-
"@
|
|
37
|
+
"@bananapus/address-registry-v6": "0.0.25",
|
|
38
|
+
"@bananapus/buyback-hook-v6": "0.0.37",
|
|
39
|
+
"@sphinx-labs/plugins": "0.33.3",
|
|
40
|
+
"@uniswap/v4-core": "1.0.2"
|
|
32
41
|
}
|
|
33
42
|
}
|
|
@@ -32,11 +32,17 @@ import {JBSuckerDeploymentConfig} from "./structs/JBSuckerDeploymentConfig.sol";
|
|
|
32
32
|
import {JBTiered721HookConfig} from "./structs/JBTiered721HookConfig.sol";
|
|
33
33
|
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
34
34
|
|
|
35
|
-
/// @notice
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
/// @notice One-stop deployer and data hook wrapper for omnichain Juicebox projects. Launches a project with a tiered
|
|
36
|
+
/// 721 hook and cross-chain suckers in a single transaction, then inserts itself as every ruleset's data hook so it can
|
|
37
|
+
/// coordinate between the 721 hook, an optional extra hook (e.g. buyback), and the sucker registry at pay/cash-out
|
|
38
|
+
/// time. At pay time it merges weight and hook specifications from both the 721 hook and the extra hook. At cash-out
|
|
39
|
+
/// time it
|
|
40
|
+
/// computes cross-chain total supply and surplus (so the bonding curve reflects all chains), grants suckers 0% cash-out
|
|
41
|
+
/// tax, and delegates tax-rate adjustments to the underlying hooks.
|
|
42
|
+
/// @dev Project NFTs sent to this contract are not recoverable. The deployer does not implement any NFT rescue
|
|
43
|
+
/// mechanism beyond `onERC721Received` for `JBProjects`. This is acceptable because the deployer should never own
|
|
44
|
+
/// project NFTs —
|
|
45
|
+
/// it creates projects and transfers ownership in the same transaction.
|
|
40
46
|
contract JBOmnichainDeployer is
|
|
41
47
|
ERC2771Context,
|
|
42
48
|
JBPermissioned,
|
|
@@ -142,10 +148,12 @@ contract JBOmnichainDeployer is
|
|
|
142
148
|
// ---------------------- external transactions ---------------------- //
|
|
143
149
|
//*********************************************************************//
|
|
144
150
|
|
|
145
|
-
/// @notice Deploy new suckers for an existing project.
|
|
146
|
-
///
|
|
147
|
-
///
|
|
148
|
-
///
|
|
151
|
+
/// @notice Deploy new cross-chain suckers for an existing project. Each sucker enables token bridging between this
|
|
152
|
+
/// chain and a peer chain. The registry also maps configured tokens on each new sucker in the same call.
|
|
153
|
+
/// @dev Only the project's owner or an operator with `JBPermissionIds.DEPLOY_SUCKERS` can call this. The salt
|
|
154
|
+
/// includes `msg.sender` for replay protection — the same sender must call on both chains for deterministic
|
|
155
|
+
/// address
|
|
156
|
+
/// matching.
|
|
149
157
|
/// @param projectId The ID of the project to deploy suckers for.
|
|
150
158
|
/// @param suckerDeploymentConfiguration The suckers to set up for the project.
|
|
151
159
|
function deploySuckersFor(
|
|
@@ -252,6 +260,7 @@ contract JBOmnichainDeployer is
|
|
|
252
260
|
/// @notice Launches new rulesets for a project with a 721 tiers hook attached, using this contract as the data
|
|
253
261
|
/// hook.
|
|
254
262
|
/// @param projectId The ID of the project to launch the rulesets for.
|
|
263
|
+
/// @param projectUri The project's metadata URI. Pass an empty string to leave it unchanged.
|
|
255
264
|
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
256
265
|
/// @param rulesetConfigurations The rulesets to launch. Custom data hooks are read from each ruleset's metadata.
|
|
257
266
|
/// @param terminalConfigurations The terminals to set up for the project.
|
|
@@ -261,6 +270,7 @@ contract JBOmnichainDeployer is
|
|
|
261
270
|
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
262
271
|
function launchRulesetsFor(
|
|
263
272
|
uint256 projectId,
|
|
273
|
+
string calldata projectUri,
|
|
264
274
|
JBOmnichain721Config memory deploy721Config,
|
|
265
275
|
JBRulesetConfig[] memory rulesetConfigurations,
|
|
266
276
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
@@ -273,6 +283,7 @@ contract JBOmnichainDeployer is
|
|
|
273
283
|
{
|
|
274
284
|
return _launchRulesetsFor({
|
|
275
285
|
projectId: projectId,
|
|
286
|
+
projectUri: projectUri,
|
|
276
287
|
deploy721Config: deploy721Config,
|
|
277
288
|
rulesetConfigurations: rulesetConfigurations,
|
|
278
289
|
terminalConfigurations: terminalConfigurations,
|
|
@@ -284,6 +295,7 @@ contract JBOmnichainDeployer is
|
|
|
284
295
|
/// @notice Launches new rulesets for a project with a default (empty-tier) 721 hook.
|
|
285
296
|
/// @dev Uses `baseCurrency` from the first ruleset and `decimals = 18` for the default 721 config.
|
|
286
297
|
/// @param projectId The ID of the project to launch the rulesets for.
|
|
298
|
+
/// @param projectUri The project's metadata URI. Pass an empty string to leave it unchanged.
|
|
287
299
|
/// @param rulesetConfigurations The rulesets to launch.
|
|
288
300
|
/// @param terminalConfigurations The terminals to set up for the project.
|
|
289
301
|
/// @param memo A memo to pass along to the emitted event.
|
|
@@ -292,6 +304,7 @@ contract JBOmnichainDeployer is
|
|
|
292
304
|
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
293
305
|
function launchRulesetsFor(
|
|
294
306
|
uint256 projectId,
|
|
307
|
+
string calldata projectUri,
|
|
295
308
|
JBRulesetConfig[] memory rulesetConfigurations,
|
|
296
309
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
297
310
|
string calldata memo,
|
|
@@ -303,6 +316,7 @@ contract JBOmnichainDeployer is
|
|
|
303
316
|
{
|
|
304
317
|
return _launchRulesetsFor({
|
|
305
318
|
projectId: projectId,
|
|
319
|
+
projectUri: projectUri,
|
|
306
320
|
deploy721Config: _default721Config(rulesetConfigurations),
|
|
307
321
|
rulesetConfigurations: rulesetConfigurations,
|
|
308
322
|
terminalConfigurations: terminalConfigurations,
|
|
@@ -382,8 +396,13 @@ contract JBOmnichainDeployer is
|
|
|
382
396
|
// ------------------------- external views -------------------------- //
|
|
383
397
|
//*********************************************************************//
|
|
384
398
|
|
|
385
|
-
/// @notice
|
|
386
|
-
///
|
|
399
|
+
/// @notice Called by the terminal before recording a cash out. Suckers get 0% tax so bridged tokens redeem at face
|
|
400
|
+
/// value. For all other holders, this function aggregates total supply and surplus across all peer chains so the
|
|
401
|
+
/// bonding curve reflects the project's global state, then delegates to the 721 hook and extra hook for further
|
|
402
|
+
/// adjustments.
|
|
403
|
+
/// @dev Part of `IJBRulesetDataHook`. The 721 hook's returned `totalSupply` and `effectiveSurplusValue` are used
|
|
404
|
+
/// when it handles cash outs (NFT redemptions use local denominators). Otherwise this contract's cross-chain values
|
|
405
|
+
/// take precedence.
|
|
387
406
|
/// @param context Standard Juicebox cash out context. See `JBBeforeCashOutRecordedContext`.
|
|
388
407
|
/// @return cashOutTaxRate The cash out tax rate, which influences the amount of terminal tokens which get cashed
|
|
389
408
|
/// out.
|
|
@@ -497,8 +516,13 @@ contract JBOmnichainDeployer is
|
|
|
497
516
|
return (cashOutTaxRate, cashOutCount, totalSupply, effectiveSurplusValue, hookSpecifications);
|
|
498
517
|
}
|
|
499
518
|
|
|
500
|
-
/// @notice
|
|
501
|
-
///
|
|
519
|
+
/// @notice Called by the terminal before recording a payment. Coordinates the 721 hook (which handles tier-based
|
|
520
|
+
/// NFT minting and split deductions) with the extra hook (e.g. buyback, which may swap for a better token price).
|
|
521
|
+
/// Merges
|
|
522
|
+
/// their weight adjustments and hook specifications into a single response for the terminal.
|
|
523
|
+
/// @dev Part of `IJBRulesetDataHook`. The 721 hook's weight already accounts for tier-split deductions. The extra
|
|
524
|
+
/// hook receives the post-split amount so it only routes funds actually entering the project. If both return
|
|
525
|
+
/// specifications, the 721 spec comes first.
|
|
502
526
|
/// @param context Standard Juicebox payment context. See `JBBeforePayRecordedContext`.
|
|
503
527
|
/// @return weight The weight which project tokens are minted relative to. This can be used to customize how many
|
|
504
528
|
/// tokens get minted by a payment.
|
|
@@ -618,8 +642,9 @@ contract JBOmnichainDeployer is
|
|
|
618
642
|
return _extraDataHookOf[projectId][rulesetId];
|
|
619
643
|
}
|
|
620
644
|
|
|
621
|
-
/// @notice
|
|
622
|
-
///
|
|
645
|
+
/// @notice Returns whether an address may mint a project's tokens on-demand. Suckers always get mint permission (so
|
|
646
|
+
/// bridged tokens can be minted on the destination chain). Otherwise delegates to the extra data hook.
|
|
647
|
+
/// @dev Part of `IJBRulesetDataHook`. The 721 hook never grants mint permission, so only the extra hook is checked.
|
|
623
648
|
/// @param projectId The ID of the project whose token can be minted.
|
|
624
649
|
/// @param ruleset The ruleset to check the token minting permission of.
|
|
625
650
|
/// @param addr The address to check the token minting permission of.
|
|
@@ -720,11 +745,12 @@ contract JBOmnichainDeployer is
|
|
|
720
745
|
internal
|
|
721
746
|
returns (uint256 projectId, IJB721TiersHook hook, address[] memory suckers)
|
|
722
747
|
{
|
|
723
|
-
//
|
|
724
|
-
projectId = PROJECTS.
|
|
748
|
+
// Reserve the project ID up front so permissionless project creations cannot invalidate hook deployment.
|
|
749
|
+
projectId = PROJECTS.createFor(address(this));
|
|
725
750
|
|
|
726
751
|
// Deploy a 721 hook and set up rulesets.
|
|
727
752
|
hook = _deploy721Hook({projectId: projectId, config: deploy721Config});
|
|
753
|
+
// slither-disable-next-line reentrancy-benign
|
|
728
754
|
rulesetConfigurations = _setup721({
|
|
729
755
|
projectId: projectId,
|
|
730
756
|
rulesetConfigurations: rulesetConfigurations,
|
|
@@ -732,18 +758,16 @@ contract JBOmnichainDeployer is
|
|
|
732
758
|
use721ForCashOut: deploy721Config.useDataHookForCashOut
|
|
733
759
|
});
|
|
734
760
|
|
|
735
|
-
// Launch the
|
|
736
|
-
// slither-disable-
|
|
737
|
-
|
|
738
|
-
projectId
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
})
|
|
746
|
-
) revert JBOmnichainDeployer_ProjectIdMismatch();
|
|
761
|
+
// Launch the rulesets for the reserved project.
|
|
762
|
+
// slither-disable-start unused-return
|
|
763
|
+
controller.launchRulesetsFor({
|
|
764
|
+
projectId: projectId,
|
|
765
|
+
projectUri: projectUri,
|
|
766
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
767
|
+
terminalConfigurations: terminalConfigurations,
|
|
768
|
+
memo: memo
|
|
769
|
+
});
|
|
770
|
+
// slither-disable-end unused-return
|
|
747
771
|
|
|
748
772
|
// Transfer the hook's ownership to the project (now that the project NFT has been minted).
|
|
749
773
|
JBOwnable(address(hook)).transferOwnershipToProject(projectId);
|
|
@@ -766,6 +790,7 @@ contract JBOmnichainDeployer is
|
|
|
766
790
|
/// @notice Internal implementation of `launchRulesetsFor`.
|
|
767
791
|
function _launchRulesetsFor(
|
|
768
792
|
uint256 projectId,
|
|
793
|
+
string calldata projectUri,
|
|
769
794
|
JBOmnichain721Config memory deploy721Config,
|
|
770
795
|
JBRulesetConfig[] memory rulesetConfigurations,
|
|
771
796
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
@@ -775,15 +800,19 @@ contract JBOmnichainDeployer is
|
|
|
775
800
|
internal
|
|
776
801
|
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
777
802
|
{
|
|
803
|
+
address owner = PROJECTS.ownerOf(projectId);
|
|
804
|
+
|
|
778
805
|
// Enforce permissions. Use LAUNCH_RULESETS (not QUEUE_RULESETS) because this function calls
|
|
779
806
|
// controller.launchRulesetsFor, which sets terminals and requires the broader launch permission.
|
|
780
|
-
_requirePermissionFrom({
|
|
781
|
-
account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.LAUNCH_RULESETS
|
|
782
|
-
});
|
|
807
|
+
_requirePermissionFrom({account: owner, projectId: projectId, permissionId: JBPermissionIds.LAUNCH_RULESETS});
|
|
783
808
|
|
|
784
|
-
_requirePermissionFrom({
|
|
785
|
-
|
|
786
|
-
|
|
809
|
+
_requirePermissionFrom({account: owner, projectId: projectId, permissionId: JBPermissionIds.SET_TERMINALS});
|
|
810
|
+
|
|
811
|
+
if (bytes(projectUri).length != 0) {
|
|
812
|
+
_requirePermissionFrom({
|
|
813
|
+
account: owner, projectId: projectId, permissionId: JBPermissionIds.SET_PROJECT_URI
|
|
814
|
+
});
|
|
815
|
+
}
|
|
787
816
|
|
|
788
817
|
// Validate that the controller matches the project's controller in the directory.
|
|
789
818
|
_validateController({projectId: projectId, controller: controller});
|
|
@@ -802,6 +831,7 @@ contract JBOmnichainDeployer is
|
|
|
802
831
|
// Configure the rulesets.
|
|
803
832
|
rulesetId = controller.launchRulesetsFor({
|
|
804
833
|
projectId: projectId,
|
|
834
|
+
projectUri: projectUri,
|
|
805
835
|
rulesetConfigurations: rulesetConfigurations,
|
|
806
836
|
terminalConfigurations: terminalConfigurations,
|
|
807
837
|
memo: memo
|
|
@@ -830,6 +860,7 @@ contract JBOmnichainDeployer is
|
|
|
830
860
|
// Revert if the project already had rulesets queued in this block, which would make our
|
|
831
861
|
// `block.timestamp + i` ruleset ID prediction incorrect.
|
|
832
862
|
uint256 latestRulesetId = controller.RULESETS().latestRulesetIdOf(projectId);
|
|
863
|
+
// forge-lint: disable-next-line(block-timestamp)
|
|
833
864
|
if (latestRulesetId >= block.timestamp) {
|
|
834
865
|
revert JBOmnichainDeployer_RulesetIdsUnpredictable();
|
|
835
866
|
}
|
|
@@ -887,9 +918,11 @@ contract JBOmnichainDeployer is
|
|
|
887
918
|
});
|
|
888
919
|
}
|
|
889
920
|
|
|
890
|
-
/// @notice
|
|
921
|
+
/// @notice Wires up each ruleset so this contract acts as the data hook wrapper. Stores the 721 hook and any extra
|
|
922
|
+
/// data hook (from the ruleset's metadata) in per-project/per-ruleset mappings, then overwrites each ruleset's
|
|
923
|
+
/// metadata to point at this contract with both pay and cash-out delegation enabled.
|
|
891
924
|
/// @dev Stores the 721 hook in `_tiered721HookOf` per-ruleset and any custom hook (from metadata) in
|
|
892
|
-
/// `_extraDataHookOf`.
|
|
925
|
+
/// `_extraDataHookOf`. Ruleset IDs are predicted as `block.timestamp + i`.
|
|
893
926
|
/// @param projectId The ID of the project to set up.
|
|
894
927
|
/// @param rulesetConfigurations The rulesets to set up.
|
|
895
928
|
/// @param hook721 The 721 tiers hook.
|
|
@@ -910,11 +943,13 @@ contract JBOmnichainDeployer is
|
|
|
910
943
|
|
|
911
944
|
// Store the 721 hook config per-ruleset.
|
|
912
945
|
// slither-disable-next-line reentrancy-benign
|
|
946
|
+
// forge-lint: disable-next-line(block-timestamp)
|
|
913
947
|
_tiered721HookOf[projectId][block.timestamp + i] =
|
|
914
948
|
JBTiered721HookConfig({hook: hook721, useDataHookForCashOut: use721ForCashOut});
|
|
915
949
|
|
|
916
950
|
// Store custom hook from metadata (same as _setup).
|
|
917
951
|
if (rulesetConfigurations[i].metadata.dataHook != address(0)) {
|
|
952
|
+
// forge-lint: disable-next-line(block-timestamp)
|
|
918
953
|
_extraDataHookOf[projectId][block.timestamp + i] = JBDeployerHookConfig({
|
|
919
954
|
dataHook: IJBRulesetDataHook(rulesetConfigurations[i].metadata.dataHook),
|
|
920
955
|
useDataHookForPay: rulesetConfigurations[i].metadata.useDataHookForPay,
|
|
@@ -9,7 +9,10 @@ import {JBDeployerHookConfig} from "../structs/JBDeployerHookConfig.sol";
|
|
|
9
9
|
import {JBOmnichain721Config} from "../structs/JBOmnichain721Config.sol";
|
|
10
10
|
import {JBSuckerDeploymentConfig} from "../structs/JBSuckerDeploymentConfig.sol";
|
|
11
11
|
|
|
12
|
-
/// @notice
|
|
12
|
+
/// @notice Interface for the omnichain deployer — a one-stop contract that launches Juicebox projects with a tiered
|
|
13
|
+
/// 721
|
|
14
|
+
/// hook and cross-chain suckers, then serves as the data hook wrapper that coordinates pay/cash-out logic across all
|
|
15
|
+
/// chains.
|
|
13
16
|
interface IJBOmnichainDeployer {
|
|
14
17
|
/// @notice Get the extra data hook for a project and ruleset.
|
|
15
18
|
/// @param projectId The ID of the project to get the extra data hook for.
|
|
@@ -100,6 +103,7 @@ interface IJBOmnichainDeployer {
|
|
|
100
103
|
|
|
101
104
|
/// @notice Launches new rulesets for a project with a 721 tiers hook attached.
|
|
102
105
|
/// @param projectId The ID of the project to launch the rulesets for.
|
|
106
|
+
/// @param projectUri The project's metadata URI. Pass an empty string to leave it unchanged.
|
|
103
107
|
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
104
108
|
/// @param rulesetConfigurations The rulesets to launch. Custom data hooks are read from each ruleset's metadata.
|
|
105
109
|
/// @param terminalConfigurations The terminals to set up for the project.
|
|
@@ -109,6 +113,7 @@ interface IJBOmnichainDeployer {
|
|
|
109
113
|
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
110
114
|
function launchRulesetsFor(
|
|
111
115
|
uint256 projectId,
|
|
116
|
+
string calldata projectUri,
|
|
112
117
|
JBOmnichain721Config memory deploy721Config,
|
|
113
118
|
JBRulesetConfig[] memory rulesetConfigurations,
|
|
114
119
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
@@ -120,6 +125,7 @@ interface IJBOmnichainDeployer {
|
|
|
120
125
|
|
|
121
126
|
/// @notice Launches new rulesets for a project with a default (empty-tier) 721 hook.
|
|
122
127
|
/// @param projectId The ID of the project to launch the rulesets for.
|
|
128
|
+
/// @param projectUri The project's metadata URI. Pass an empty string to leave it unchanged.
|
|
123
129
|
/// @param rulesetConfigurations The rulesets to launch.
|
|
124
130
|
/// @param terminalConfigurations The terminals to set up for the project.
|
|
125
131
|
/// @param memo A memo to pass along to the emitted event.
|
|
@@ -128,6 +134,7 @@ interface IJBOmnichainDeployer {
|
|
|
128
134
|
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
129
135
|
function launchRulesetsFor(
|
|
130
136
|
uint256 projectId,
|
|
137
|
+
string calldata projectUri,
|
|
131
138
|
JBRulesetConfig[] memory rulesetConfigurations,
|
|
132
139
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
133
140
|
string calldata memo,
|
|
@@ -3,6 +3,11 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
|
|
5
5
|
|
|
6
|
+
/// @notice Configuration for an extra data hook (e.g. a buyback hook) that the omnichain deployer delegates to
|
|
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.
|
|
6
11
|
struct JBDeployerHookConfig {
|
|
7
12
|
IJBRulesetDataHook dataHook;
|
|
8
13
|
bool useDataHookForPay;
|
|
@@ -3,6 +3,10 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
5
5
|
|
|
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
|
|
9
|
+
/// redemptions.
|
|
6
10
|
struct JBTiered721HookConfig {
|
|
7
11
|
IJB721TiersHook hook;
|
|
8
12
|
bool useDataHookForCashOut;
|
package/ADMINISTRATION.md
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Administration
|
|
2
|
-
|
|
3
|
-
## At A Glance
|
|
4
|
-
|
|
5
|
-
| Item | Details |
|
|
6
|
-
| --- | --- |
|
|
7
|
-
| Scope | Omnichain launch orchestration and wrapper behavior |
|
|
8
|
-
| Control posture | Mixed deployer logic, project permissions, and registry trust |
|
|
9
|
-
| Highest-risk actions | Wrong hook composition, wrong sucker wiring, and bad registry trust |
|
|
10
|
-
| Recovery posture | Often requires redeploying or re-launching around bad wiring |
|
|
11
|
-
|
|
12
|
-
## Purpose
|
|
13
|
-
|
|
14
|
-
This repo controls how omnichain projects are launched and wrapped, not the low-level runtime logic of suckers or 721 hooks.
|
|
15
|
-
|
|
16
|
-
## Control Model
|
|
17
|
-
|
|
18
|
-
- launch paths are largely permissionless for new projects
|
|
19
|
-
- later ruleset changes depend on project permissions
|
|
20
|
-
- registry and sucker trust surfaces can widen authority if misconfigured
|
|
21
|
-
|
|
22
|
-
## Recovery
|
|
23
|
-
|
|
24
|
-
- bad launch wiring usually means a new deployment path rather than a local patch
|
|
25
|
-
|
|
26
|
-
## Admin Boundaries
|
|
27
|
-
|
|
28
|
-
- this repo does not override locked runtime behavior in sibling repos
|
|
29
|
-
|
package/ARCHITECTURE.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
`nana-omnichain-deployers-v6` packages a Juicebox project, a 721 hook, and sucker deployment into one omnichain launch surface.
|
|
6
|
-
|
|
7
|
-
## System Overview
|
|
8
|
-
|
|
9
|
-
`JBOmnichainDeployer` launches the project, stores per-ruleset hook composition, and wraps sucker behavior so bridge-triggered flows can bypass project-specific logic where intended.
|
|
10
|
-
|
|
11
|
-
## Core Invariants
|
|
12
|
-
|
|
13
|
-
- launch wiring must match the intended omnichain project shape
|
|
14
|
-
- hook composition must stay consistent with the created ruleset IDs
|
|
15
|
-
- sucker-specific privileged paths must remain limited to trusted suckers
|
|
16
|
-
- project NFT ownership and hook ownership must end in the intended place
|
|
17
|
-
|
|
18
|
-
## Trust Boundaries
|
|
19
|
-
|
|
20
|
-
- bridge runtime trust lives in `nana-suckers-v6`
|
|
21
|
-
- 721 runtime trust lives in `nana-721-hook-v6`
|
|
22
|
-
- this repo mainly owns orchestration and wrapper semantics
|
|
23
|
-
|
|
24
|
-
## Security Model
|
|
25
|
-
|
|
26
|
-
- the main risks are hook composition, ruleset ID prediction, and registry-trusted sucker bypasses
|
|
27
|
-
- this repo is not the source of underlying bridge or 721 behavior, but it can wire them together incorrectly
|
|
28
|
-
|
|
29
|
-
## Source Map
|
|
30
|
-
|
|
31
|
-
- `src/JBOmnichainDeployer.sol`
|
package/AUDIT_INSTRUCTIONS.md
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Audit Instructions
|
|
2
|
-
|
|
3
|
-
Audit this repo as an orchestration layer that composes 721 hooks, suckers, and optional extra data hooks.
|
|
4
|
-
|
|
5
|
-
## Audit Objective
|
|
6
|
-
|
|
7
|
-
Find issues that:
|
|
8
|
-
|
|
9
|
-
- launch the wrong project shape
|
|
10
|
-
- miscompose hooks or wrapper behavior
|
|
11
|
-
- grant privileged sucker behavior to the wrong addresses
|
|
12
|
-
- create cross-chain drift or bad deterministic assumptions
|
|
13
|
-
|
|
14
|
-
## Scope
|
|
15
|
-
|
|
16
|
-
In scope:
|
|
17
|
-
|
|
18
|
-
- `src/JBOmnichainDeployer.sol`
|
|
19
|
-
- related tests under `test/`
|
|
20
|
-
|
|
21
|
-
## Start Here
|
|
22
|
-
|
|
23
|
-
1. `src/JBOmnichainDeployer.sol`
|
|
24
|
-
|
|
25
|
-
## Verification
|
|
26
|
-
|
|
27
|
-
- `npm install`
|
|
28
|
-
- `forge build`
|
|
29
|
-
- `forge test`
|
package/RISKS.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Omnichain Deployers Risk Register
|
|
2
|
-
|
|
3
|
-
This file covers the risks in the deployer layer that launches Juicebox projects across chains while composing 721 hooks, suckers, and optional custom data hooks.
|
|
4
|
-
|
|
5
|
-
## How To Use This File
|
|
6
|
-
|
|
7
|
-
- Read `Priority risks` first. They capture the highest-blast-radius deployment and cash-out assumptions.
|
|
8
|
-
- Treat `Invariants to verify` as required checks for any new omnichain deployment flow.
|
|
9
|
-
|
|
10
|
-
## Priority Risks
|
|
11
|
-
|
|
12
|
-
| Priority | Risk | Why it matters | Primary controls |
|
|
13
|
-
|----------|------|----------------|------------------|
|
|
14
|
-
| P0 | Registry-trusted sucker bypass | This deployer gives suckers privileged cash-out behavior based on registry answers. A bad registry entry can affect many projects. | Registry allowlists, deployment verification, and explicit registry scrutiny. |
|
|
15
|
-
| P1 | Cross-chain deployment drift | Omnichain assumptions fail if chain-specific wiring, peers, or composed hooks do not match. | Deterministic deploy ordering, parity checks, and post-deploy peer verification. |
|
|
16
|
-
| P1 | Data-hook composition mistakes | The deployer wraps or forwards custom data hooks. A bad composition can alter pay or cash-out semantics unexpectedly. | Integration tests and careful forwarding review. |
|
|
17
|
-
|
|
18
|
-
## 1. Trust Assumptions
|
|
19
|
-
|
|
20
|
-
- **Trusted forwarder is trusted.**
|
|
21
|
-
- **Sucker registry answers are trusted.**
|
|
22
|
-
- **Controller trust matters.**
|
|
23
|
-
- **Extra data hooks are trusted code.**
|
|
24
|
-
|
|
25
|
-
## 2. Economic Risks
|
|
26
|
-
|
|
27
|
-
- **Sucker cashout bypass exists for registered suckers.**
|
|
28
|
-
- **Extra data hooks can manipulate weight or cash-out behavior.**
|
|
29
|
-
- **721 hook amount splitting can zero out project amount in edge cases.**
|
|
30
|
-
- **Cross-chain sender dependence affects deterministic sucker salts.**
|
|
31
|
-
|
|
32
|
-
## 3. Access Control
|
|
33
|
-
|
|
34
|
-
- **Wildcard `MAP_SUCKER_TOKEN` permission is broad.**
|
|
35
|
-
- **`launchRulesetsFor` requires combined permissions.**
|
|
36
|
-
- **`launchProjectFor` is intentionally permissionless for new projects.**
|
|
37
|
-
|
|
38
|
-
## 4. DoS Vectors
|
|
39
|
-
|
|
40
|
-
- **Ruleset ID collision can block queueing.**
|
|
41
|
-
- **External hook reverts can block pay or cash-out flows.**
|
|
42
|
-
- **721 hook deployment revert blocks launch.**
|
|
43
|
-
- **Non-safe NFT transfers can still strand assets.**
|
|
44
|
-
|
|
45
|
-
## 5. Reentrancy Surface
|
|
46
|
-
|
|
47
|
-
- **`launchProjectFor` makes several external calls in sequence.**
|
|
48
|
-
- **`beforePayRecordedWith` delegates to external hooks.**
|
|
49
|
-
- **`beforeCashOutRecordedWith` delegates to external hooks.**
|
|
50
|
-
- **There is no `ReentrancyGuard`.** The deployer relies on being effectively stateless during pay and cash-out operations.
|
|
51
|
-
|
|
52
|
-
## 6. Integration Risks
|
|
53
|
-
|
|
54
|
-
- **Hook config is keyed by predicted ruleset ID.**
|
|
55
|
-
- **Carried-forward 721 hook behavior on queue depends on prior ruleset state.**
|
|
56
|
-
- **ERC721Receiver restrictions are narrow but non-safe transfers can still strand assets.**
|
|
57
|
-
- **Empty simplified launch config reverts.**
|
|
58
|
-
|
|
59
|
-
## 7. Invariants To Verify
|
|
60
|
-
|
|
61
|
-
- launched projects point at the intended controller
|
|
62
|
-
- stored 721 hook config exists for every ruleset created through this deployer
|
|
63
|
-
- sucker cashouts always get the intended zero-tax path
|
|
64
|
-
- self-reference prevention holds after setup
|
|
65
|
-
- the project NFT ends owned by the intended owner
|
|
66
|
-
|
|
67
|
-
## 8. Accepted Behaviors
|
|
68
|
-
|
|
69
|
-
### 8.1 Controller validation is skipped during initial launch
|
|
70
|
-
|
|
71
|
-
Pre-launch controller validation is impossible because the project does not yet exist. The accepted safeguard is the post-launch project ID match check.
|
|
72
|
-
|
|
73
|
-
### 8.2 Registered suckers receive 0% cashout tax
|
|
74
|
-
|
|
75
|
-
This is intentional and shares the same trust boundary as the sucker registry.
|
|
76
|
-
|
|
77
|
-
## 9. Accepted Security Risks
|
|
78
|
-
|
|
79
|
-
Documented risks that were reviewed and accepted.
|
|
80
|
-
|
|
81
|
-
### Configuration Risks
|
|
82
|
-
|
|
83
|
-
**Unvalidated extra data hooks can brick live flows.** *(Minor)*
|
|
84
|
-
Extra data hooks provided by the project owner in `_setup721` configuration can fail and brick live pay/cashout flows. Accepted because this is self-inflicted misconfiguration — only the project owner can set these hooks.
|
|
85
|
-
|
|
86
|
-
**Missing hook721 alias check enables double invocation.** *(Minor)*
|
|
87
|
-
If the project owner configures the 721 hook as both the primary hook and as an extra data hook, it could be invoked twice. Accepted because this is self-inflicted misconfiguration — the deployer correctly processes each hook independently.
|
|
88
|
-
|
|
89
|
-
### Hook Selection
|
|
90
|
-
|
|
91
|
-
**ApprovalExpected rulesets excluded from hook carry-forward.**
|
|
92
|
-
When no new tiers are provided, the deployer carries forward the 721 hook from the most recent approved ruleset. Rulesets with `ApprovalExpected` status are intentionally excluded even though they may become active. Hook selection is irreversible — if the pending ruleset is later rejected by the approval hook, we'd have locked in a hook from a ruleset that never became active. The deployer falls back to the current (already-approved) ruleset in this case.
|
|
93
|
-
|
|
94
|
-
### Cross-Chain Deployment
|
|
95
|
-
|
|
96
|
-
**`_msgSender()` in deployment salt breaks cross-chain determinism.** *(Minor)*
|
|
97
|
-
`deploySuckersFor` includes `_msgSender()` in the CREATE2 salt, which means the same deployment from different callers produces different addresses across chains. Accepted because this is intentional replay protection — prevents frontrunning of cross-chain deployments.
|
package/SKILLS.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Juicebox Omnichain Deployers
|
|
2
|
-
|
|
3
|
-
## Use This File For
|
|
4
|
-
|
|
5
|
-
- Use this file when the task involves omnichain project launch, sucker deployment, or wrapped 721-hook composition.
|
|
6
|
-
- Start here, then decide whether the issue is in launch orchestration, hook composition, or bridge-specific runtime behavior.
|
|
7
|
-
|
|
8
|
-
## Read This Next
|
|
9
|
-
|
|
10
|
-
| If you need... | Open this next |
|
|
11
|
-
|---|---|
|
|
12
|
-
| Repo overview and architecture | [`README.md`](./README.md), [`ARCHITECTURE.md`](./ARCHITECTURE.md) |
|
|
13
|
-
| Main deployer | [`src/JBOmnichainDeployer.sol`](./src/JBOmnichainDeployer.sol) |
|
|
14
|
-
| Bridge runtime | [`../nana-suckers-v6/src/JBSucker.sol`](../nana-suckers-v6/src/JBSucker.sol) |
|
|
15
|
-
| 721 hook runtime | [`../nana-721-hook-v6/src/JB721TiersHook.sol`](../nana-721-hook-v6/src/JB721TiersHook.sol) |
|
|
16
|
-
|
|
17
|
-
## Purpose
|
|
18
|
-
|
|
19
|
-
Orchestration and wrapper layer for launching projects with suckers and a 721 hook already wired in.
|
|
20
|
-
|
|
21
|
-
## Working Rules
|
|
22
|
-
|
|
23
|
-
- Start in [`src/JBOmnichainDeployer.sol`](./src/JBOmnichainDeployer.sol).
|
|
24
|
-
- Treat ruleset ID prediction as a real implementation dependency.
|
|
25
|
-
- Keep wrapper behavior and the underlying 721 or sucker behavior separate in your reasoning.
|