@bananapus/omnichain-deployers-v6 0.0.8 → 0.0.9
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/package.json +1 -1
- package/src/JBOmnichainDeployer.sol +124 -317
- package/src/interfaces/IJBOmnichainDeployer.sol +25 -84
- package/src/structs/JBOmnichain721Config.sol +15 -0
- package/test/JBOmnichainDeployer.t.sol +3 -1
- package/test/JBOmnichainDeployerGuard.t.sol +17 -7
- package/test/OmnichainDeployerAttacks.t.sol +3 -1
- package/test/OmnichainDeployerEdgeCases.t.sol +12 -10
- package/test/Tiered721HookComposition.t.sol +99 -524
- package/test/fork/OmnichainForkTestBase.sol +32 -45
- package/test/fork/TestOmnichain721QueueAndAdjust.t.sol +31 -130
- package/test/fork/TestOmnichainStressFork.t.sol +3 -1
- package/test/regression/HookOwnershipTransfer.t.sol +27 -19
- package/test/regression/ValidateController.t.sol +7 -3
package/package.json
CHANGED
|
@@ -7,12 +7,6 @@ import {Context} from "@openzeppelin/contracts/utils/Context.sol";
|
|
|
7
7
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
8
8
|
import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
9
9
|
import {IJB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookProjectDeployer.sol";
|
|
10
|
-
import {JBDeploy721TiersHookConfig} from "@bananapus/721-hook-v6/src/structs/JBDeploy721TiersHookConfig.sol";
|
|
11
|
-
import {JBLaunchProjectConfig} from "@bananapus/721-hook-v6/src/structs/JBLaunchProjectConfig.sol";
|
|
12
|
-
import {JBLaunchRulesetsConfig} from "@bananapus/721-hook-v6/src/structs/JBLaunchRulesetsConfig.sol";
|
|
13
|
-
import {JBPayDataHookRulesetConfig} from "@bananapus/721-hook-v6/src/structs/JBPayDataHookRulesetConfig.sol";
|
|
14
|
-
import {JBPayDataHookRulesetMetadata} from "@bananapus/721-hook-v6/src/structs/JBPayDataHookRulesetMetadata.sol";
|
|
15
|
-
import {JBQueueRulesetsConfig} from "@bananapus/721-hook-v6/src/structs/JBQueueRulesetsConfig.sol";
|
|
16
10
|
import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
|
|
17
11
|
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
18
12
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
@@ -28,7 +22,6 @@ import {JBPermissionsData} from "@bananapus/core-v6/src/structs/JBPermissionsDat
|
|
|
28
22
|
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
29
23
|
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
30
24
|
import {JBTokenAmount} from "@bananapus/core-v6/src/structs/JBTokenAmount.sol";
|
|
31
|
-
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
32
25
|
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
33
26
|
import {JBOwnable} from "@bananapus/ownable-v6/src/JBOwnable.sol";
|
|
34
27
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
@@ -38,6 +31,7 @@ import {mulDiv} from "@prb/math/src/Common.sol";
|
|
|
38
31
|
|
|
39
32
|
import {IJBOmnichainDeployer} from "./interfaces/IJBOmnichainDeployer.sol";
|
|
40
33
|
import {JBDeployerHookConfig} from "./structs/JBDeployerHookConfig.sol";
|
|
34
|
+
import {JBOmnichain721Config} from "./structs/JBOmnichain721Config.sol";
|
|
41
35
|
import {JBSuckerDeploymentConfig} from "./structs/JBSuckerDeploymentConfig.sol";
|
|
42
36
|
import {JBTiered721HookConfig} from "./structs/JBTiered721HookConfig.sol";
|
|
43
37
|
|
|
@@ -358,174 +352,27 @@ contract JBOmnichainDeployer is
|
|
|
358
352
|
});
|
|
359
353
|
}
|
|
360
354
|
|
|
361
|
-
/// @notice
|
|
355
|
+
/// @notice Creates a project, optionally with a 721 tiers hook attached, and with suckers.
|
|
356
|
+
/// @dev If `deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0`, a 721 hook is deployed and
|
|
357
|
+
/// attached.
|
|
362
358
|
/// @param owner The address to set as the owner of the project. The ERC-721 which confers this project's ownership
|
|
363
359
|
/// will be sent to this address.
|
|
364
|
-
/// @param
|
|
365
|
-
///
|
|
366
|
-
///
|
|
367
|
-
/// @param
|
|
368
|
-
/// cross-chain deterministic addresses require the same sender on each chain.
|
|
369
|
-
/// @param suckerDeploymentConfiguration The suckers to set up for the project. Suckers facilitate cross-chain
|
|
370
|
-
/// token transfers between peer projects on different networks.
|
|
371
|
-
/// @param controller The controller to use for launching the project.
|
|
372
|
-
/// @param dataHookConfig The custom data hook config to use alongside the 721 hook.
|
|
373
|
-
/// @return projectId The ID of the newly launched project.
|
|
374
|
-
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
375
|
-
function launch721ProjectFor(
|
|
376
|
-
address owner,
|
|
377
|
-
JBDeploy721TiersHookConfig calldata deployTiersHookConfig,
|
|
378
|
-
JBLaunchProjectConfig calldata launchProjectConfig,
|
|
379
|
-
JBSuckerDeploymentConfig calldata suckerDeploymentConfiguration,
|
|
380
|
-
IJBController controller,
|
|
381
|
-
JBDeployerHookConfig calldata dataHookConfig,
|
|
382
|
-
bytes32 salt
|
|
383
|
-
)
|
|
384
|
-
external
|
|
385
|
-
override
|
|
386
|
-
returns (uint256 projectId, IJB721TiersHook hook, address[] memory suckers)
|
|
387
|
-
{
|
|
388
|
-
// Get the next project ID.
|
|
389
|
-
projectId = PROJECTS.count() + 1;
|
|
390
|
-
|
|
391
|
-
// Deploy the hook.
|
|
392
|
-
// Note: the salt includes `_msgSender()` for replay protection. Cross-chain deterministic
|
|
393
|
-
// address matching requires using the same sender address on each chain.
|
|
394
|
-
hook = HOOK_DEPLOYER.deployHookFor({
|
|
395
|
-
projectId: projectId,
|
|
396
|
-
deployTiersHookConfig: deployTiersHookConfig,
|
|
397
|
-
salt: salt == bytes32(0) ? bytes32(0) : keccak256(abi.encode(_msgSender(), salt))
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
// Convert the 721 ruleset configurations to regular ruleset configurations.
|
|
401
|
-
JBRulesetConfig[] memory rulesetConfigurations =
|
|
402
|
-
_from721Config({launchProjectConfig: launchProjectConfig.rulesetConfigurations});
|
|
403
|
-
|
|
404
|
-
// Store the 721 hook per-ruleset and set this contract as data hook.
|
|
405
|
-
rulesetConfigurations = _setup721({
|
|
406
|
-
projectId: projectId,
|
|
407
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
408
|
-
hook721: hook,
|
|
409
|
-
customHook: dataHookConfig
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
// Launch the project, and sanity check the project ID.
|
|
413
|
-
// slither-disable-next-line reentrancy-benign
|
|
414
|
-
if (
|
|
415
|
-
projectId
|
|
416
|
-
!= controller.launchProjectFor({
|
|
417
|
-
owner: address(this),
|
|
418
|
-
projectUri: launchProjectConfig.projectUri,
|
|
419
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
420
|
-
terminalConfigurations: launchProjectConfig.terminalConfigurations,
|
|
421
|
-
memo: launchProjectConfig.memo
|
|
422
|
-
})
|
|
423
|
-
) revert JBOmnichainDeployer_ProjectIdMismatch();
|
|
424
|
-
|
|
425
|
-
// Transfer the hook's ownership to the project.
|
|
426
|
-
JBOwnable(address(hook)).transferOwnershipToProject(projectId);
|
|
427
|
-
|
|
428
|
-
// Deploy the suckers (if applicable).
|
|
429
|
-
if (suckerDeploymentConfiguration.salt != bytes32(0)) {
|
|
430
|
-
// Deploy the suckers.
|
|
431
|
-
// slither-disable-next-line unused-return
|
|
432
|
-
suckers = SUCKER_REGISTRY.deploySuckersFor({
|
|
433
|
-
projectId: projectId,
|
|
434
|
-
salt: keccak256(abi.encode(suckerDeploymentConfiguration.salt, _msgSender())),
|
|
435
|
-
configurations: suckerDeploymentConfiguration.deployerConfigurations
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Transfer ownership of the project to the owner.
|
|
440
|
-
PROJECTS.transferFrom(address(this), owner, projectId);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/// @notice Launches new rulesets for a project with a 721 tiers hook attached, using this contract as the data
|
|
444
|
-
/// hook.
|
|
445
|
-
/// @param projectId The ID of the project to launch the rulesets for.
|
|
446
|
-
/// @param deployTiersHookConfig Configuration which dictates the behavior of the 721 tiers hook which is being
|
|
447
|
-
/// deployed.
|
|
448
|
-
/// @param launchRulesetsConfig Configuration which dictates the behavior of the rulesets which are being launched.
|
|
449
|
-
/// @param salt A salt to use for the deterministic deployment. Combined with `_msgSender()` internally, so
|
|
450
|
-
/// cross-chain deterministic addresses require the same sender on each chain.
|
|
451
|
-
/// @param dataHookConfig The custom data hook config to use alongside the 721 hook.
|
|
452
|
-
/// @return rulesetId The ID of the newly launched rulesets.
|
|
453
|
-
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
454
|
-
function launch721RulesetsFor(
|
|
455
|
-
uint256 projectId,
|
|
456
|
-
JBDeploy721TiersHookConfig memory deployTiersHookConfig,
|
|
457
|
-
JBLaunchRulesetsConfig calldata launchRulesetsConfig,
|
|
458
|
-
IJBController controller,
|
|
459
|
-
JBDeployerHookConfig calldata dataHookConfig,
|
|
460
|
-
bytes32 salt
|
|
461
|
-
)
|
|
462
|
-
external
|
|
463
|
-
override
|
|
464
|
-
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
465
|
-
{
|
|
466
|
-
// Enforce permissions.
|
|
467
|
-
_requirePermissionFrom({
|
|
468
|
-
account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.QUEUE_RULESETS
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
_requirePermissionFrom({
|
|
472
|
-
account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.SET_TERMINALS
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
// Validate that the controller matches the project's controller in the directory.
|
|
476
|
-
_validateController({projectId: projectId, controller: controller});
|
|
477
|
-
|
|
478
|
-
// Deploy the hook.
|
|
479
|
-
// Note: the salt includes `_msgSender()` for replay protection. Cross-chain deterministic
|
|
480
|
-
// address matching requires using the same sender address on each chain.
|
|
481
|
-
hook = HOOK_DEPLOYER.deployHookFor({
|
|
482
|
-
projectId: projectId,
|
|
483
|
-
deployTiersHookConfig: deployTiersHookConfig,
|
|
484
|
-
salt: salt == bytes32(0) ? bytes32(0) : keccak256(abi.encode(_msgSender(), salt))
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
// Transfer the hook's ownership to the project.
|
|
488
|
-
JBOwnable(address(hook)).transferOwnershipToProject(projectId);
|
|
489
|
-
|
|
490
|
-
// Convert the 721 ruleset configurations to regular ruleset configurations.
|
|
491
|
-
JBRulesetConfig[] memory rulesetConfigurations =
|
|
492
|
-
_from721Config({launchProjectConfig: launchRulesetsConfig.rulesetConfigurations});
|
|
493
|
-
|
|
494
|
-
// Store the 721 hook per-ruleset and set this contract as data hook.
|
|
495
|
-
// slither-disable-next-line reentrancy-benign
|
|
496
|
-
rulesetConfigurations = _setup721({
|
|
497
|
-
projectId: projectId,
|
|
498
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
499
|
-
hook721: hook,
|
|
500
|
-
customHook: dataHookConfig
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// Configure the rulesets.
|
|
504
|
-
rulesetId = controller.launchRulesetsFor({
|
|
505
|
-
projectId: projectId,
|
|
506
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
507
|
-
terminalConfigurations: launchRulesetsConfig.terminalConfigurations,
|
|
508
|
-
memo: launchRulesetsConfig.memo
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
/// @notice Creates a project with suckers.
|
|
513
|
-
/// @dev This will mint the project's ERC-721 to the `owner`'s address, queue the specified rulesets, and set up the
|
|
514
|
-
/// specified splits and terminals. Each operation within this transaction can be done in sequence separately.
|
|
515
|
-
/// @dev Anyone can deploy a project to any `owner`'s address.
|
|
516
|
-
/// @param owner The project's owner. The project ERC-721 will be minted to this address.
|
|
517
|
-
/// @param projectUri The project's metadata URI. This is typically an IPFS hash, optionally with the `ipfs://`
|
|
518
|
-
/// prefix. This can be updated by the project's owner.
|
|
519
|
-
/// @param rulesetConfigurations The rulesets to queue.
|
|
360
|
+
/// @param projectUri The project's metadata URI.
|
|
361
|
+
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt). If no tiers are
|
|
362
|
+
/// configured, no 721 hook is deployed.
|
|
363
|
+
/// @param rulesetConfigurations The rulesets to queue. Custom data hooks are read from each ruleset's metadata.
|
|
520
364
|
/// @param terminalConfigurations The terminals to set up for the project.
|
|
521
365
|
/// @param memo A memo to pass along to the emitted event.
|
|
522
366
|
/// @param suckerDeploymentConfiguration The suckers to set up for the project. Suckers facilitate cross-chain
|
|
523
367
|
/// token transfers between peer projects on different networks.
|
|
524
368
|
/// @param controller The controller to use for launching the project.
|
|
525
|
-
/// @return projectId The project
|
|
369
|
+
/// @return projectId The ID of the newly launched project.
|
|
370
|
+
/// @return hook The 721 tiers hook that was deployed for the project (`address(0)` if none).
|
|
371
|
+
/// @return suckers The addresses of the deployed suckers.
|
|
526
372
|
function launchProjectFor(
|
|
527
373
|
address owner,
|
|
528
374
|
string calldata projectUri,
|
|
375
|
+
JBOmnichain721Config calldata deploy721Config,
|
|
529
376
|
JBRulesetConfig[] memory rulesetConfigurations,
|
|
530
377
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
531
378
|
string calldata memo,
|
|
@@ -534,14 +381,26 @@ contract JBOmnichainDeployer is
|
|
|
534
381
|
)
|
|
535
382
|
external
|
|
536
383
|
override
|
|
537
|
-
returns (uint256 projectId, address[] memory suckers)
|
|
384
|
+
returns (uint256 projectId, IJB721TiersHook hook, address[] memory suckers)
|
|
538
385
|
{
|
|
539
386
|
// Get the next project ID.
|
|
540
387
|
projectId = PROJECTS.count() + 1;
|
|
541
388
|
|
|
542
|
-
|
|
389
|
+
// Deploy the 721 hook if tiers are configured, otherwise use the non-721 setup path.
|
|
390
|
+
if (deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0) {
|
|
391
|
+
hook = _deploy721Hook(projectId, deploy721Config);
|
|
392
|
+
rulesetConfigurations = _setup721({
|
|
393
|
+
projectId: projectId,
|
|
394
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
395
|
+
hook721: hook,
|
|
396
|
+
use721ForCashOut: deploy721Config.useDataHookForCashOut
|
|
397
|
+
});
|
|
398
|
+
} else {
|
|
399
|
+
rulesetConfigurations = _setup({projectId: projectId, rulesetConfigurations: rulesetConfigurations});
|
|
400
|
+
}
|
|
543
401
|
|
|
544
|
-
// Launch the project.
|
|
402
|
+
// Launch the project, and sanity check the project ID.
|
|
403
|
+
// slither-disable-next-line reentrancy-benign
|
|
545
404
|
if (
|
|
546
405
|
projectId
|
|
547
406
|
!= controller.launchProjectFor({
|
|
@@ -555,8 +414,6 @@ contract JBOmnichainDeployer is
|
|
|
555
414
|
|
|
556
415
|
// Deploy the suckers (if applicable).
|
|
557
416
|
if (suckerDeploymentConfiguration.salt != bytes32(0)) {
|
|
558
|
-
// Deploy the suckers.
|
|
559
|
-
// Note: the salt includes `_msgSender()` for replay protection (see above).
|
|
560
417
|
// slither-disable-next-line unused-return
|
|
561
418
|
suckers = SUCKER_REGISTRY.deploySuckersFor({
|
|
562
419
|
projectId: projectId,
|
|
@@ -569,23 +426,30 @@ contract JBOmnichainDeployer is
|
|
|
569
426
|
PROJECTS.transferFrom(address(this), owner, projectId);
|
|
570
427
|
}
|
|
571
428
|
|
|
572
|
-
/// @notice Launches new rulesets for a project, using this contract as
|
|
429
|
+
/// @notice Launches new rulesets for a project, optionally with a 721 tiers hook attached, using this contract as
|
|
430
|
+
/// the data hook.
|
|
431
|
+
/// @dev If `deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0`, a 721 hook is deployed and
|
|
432
|
+
/// attached.
|
|
573
433
|
/// @param projectId The ID of the project to launch the rulesets for.
|
|
574
|
-
/// @param
|
|
434
|
+
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt). If no tiers are
|
|
435
|
+
/// configured, no 721 hook is deployed.
|
|
436
|
+
/// @param rulesetConfigurations The rulesets to launch. Custom data hooks are read from each ruleset's metadata.
|
|
575
437
|
/// @param terminalConfigurations The terminals to set up for the project.
|
|
576
438
|
/// @param memo A memo to pass along to the emitted event.
|
|
577
439
|
/// @param controller The controller to use for launching the rulesets.
|
|
578
440
|
/// @return rulesetId The ID of the newly launched rulesets.
|
|
441
|
+
/// @return hook The 721 tiers hook that was deployed for the project (`address(0)` if none).
|
|
579
442
|
function launchRulesetsFor(
|
|
580
443
|
uint256 projectId,
|
|
581
|
-
|
|
444
|
+
JBOmnichain721Config memory deploy721Config,
|
|
445
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
582
446
|
JBTerminalConfig[] calldata terminalConfigurations,
|
|
583
447
|
string calldata memo,
|
|
584
448
|
IJBController controller
|
|
585
449
|
)
|
|
586
450
|
external
|
|
587
451
|
override
|
|
588
|
-
returns (uint256)
|
|
452
|
+
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
589
453
|
{
|
|
590
454
|
// Enforce permissions.
|
|
591
455
|
_requirePermissionFrom({
|
|
@@ -599,9 +463,24 @@ contract JBOmnichainDeployer is
|
|
|
599
463
|
// Validate that the controller matches the project's controller in the directory.
|
|
600
464
|
_validateController({projectId: projectId, controller: controller});
|
|
601
465
|
|
|
602
|
-
|
|
466
|
+
// Deploy the 721 hook if tiers are configured, otherwise use the non-721 setup path.
|
|
467
|
+
if (deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0) {
|
|
468
|
+
hook = _deploy721Hook(projectId, deploy721Config);
|
|
469
|
+
// slither-disable-next-line reentrancy-benign
|
|
470
|
+
rulesetConfigurations = _setup721({
|
|
471
|
+
projectId: projectId,
|
|
472
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
473
|
+
hook721: hook,
|
|
474
|
+
use721ForCashOut: deploy721Config.useDataHookForCashOut
|
|
475
|
+
});
|
|
476
|
+
} else {
|
|
477
|
+
rulesetConfigurations = _setup({projectId: projectId, rulesetConfigurations: rulesetConfigurations});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Configure the rulesets.
|
|
481
|
+
rulesetId = controller.launchRulesetsFor({
|
|
603
482
|
projectId: projectId,
|
|
604
|
-
rulesetConfigurations:
|
|
483
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
605
484
|
terminalConfigurations: terminalConfigurations,
|
|
606
485
|
memo: memo
|
|
607
486
|
});
|
|
@@ -615,88 +494,28 @@ contract JBOmnichainDeployer is
|
|
|
615
494
|
return IERC721Receiver.onERC721Received.selector;
|
|
616
495
|
}
|
|
617
496
|
|
|
618
|
-
/// @notice Queues new rulesets for a project with a 721 tiers hook attached, using this contract as the
|
|
497
|
+
/// @notice Queues new rulesets for a project, optionally with a 721 tiers hook attached, using this contract as the
|
|
498
|
+
/// data hook.
|
|
499
|
+
/// @dev If `deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0`, a 721 hook is deployed and
|
|
500
|
+
/// attached.
|
|
619
501
|
/// @param projectId The ID of the project to queue the rulesets for.
|
|
620
|
-
/// @param
|
|
621
|
-
/// deployed.
|
|
622
|
-
/// @param
|
|
623
|
-
/// @param salt A salt to use for the deterministic deployment. Combined with `_msgSender()` internally, so
|
|
624
|
-
/// cross-chain deterministic addresses require the same sender on each chain.
|
|
625
|
-
/// @param dataHookConfig The custom data hook config to use alongside the 721 hook.
|
|
626
|
-
/// @return rulesetId The ID of the newly queued rulesets.
|
|
627
|
-
/// @return hook The 721 tiers hook that was deployed for the project.
|
|
628
|
-
function queue721RulesetsOf(
|
|
629
|
-
uint256 projectId,
|
|
630
|
-
JBDeploy721TiersHookConfig memory deployTiersHookConfig,
|
|
631
|
-
JBQueueRulesetsConfig calldata queueRulesetsConfig,
|
|
632
|
-
IJBController controller,
|
|
633
|
-
JBDeployerHookConfig calldata dataHookConfig,
|
|
634
|
-
bytes32 salt
|
|
635
|
-
)
|
|
636
|
-
external
|
|
637
|
-
override
|
|
638
|
-
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
639
|
-
{
|
|
640
|
-
// Enforce permissions.
|
|
641
|
-
_requirePermissionFrom({
|
|
642
|
-
account: PROJECTS.ownerOf(projectId), projectId: projectId, permissionId: JBPermissionIds.QUEUE_RULESETS
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
// Validate that the controller matches the project's controller in the directory.
|
|
646
|
-
_validateController({projectId: projectId, controller: controller});
|
|
647
|
-
|
|
648
|
-
// Revert if the project already had rulesets queued in this block, which would make our
|
|
649
|
-
// `block.timestamp + i` ruleset ID prediction incorrect.
|
|
650
|
-
if (controller.RULESETS().latestRulesetIdOf(projectId) >= block.timestamp) {
|
|
651
|
-
revert JBOmnichainDeployer_RulesetIdsUnpredictable();
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
// Deploy the hook.
|
|
655
|
-
// Note: the salt includes `_msgSender()` for replay protection. Cross-chain deterministic
|
|
656
|
-
// address matching requires using the same sender address on each chain.
|
|
657
|
-
hook = HOOK_DEPLOYER.deployHookFor({
|
|
658
|
-
projectId: projectId,
|
|
659
|
-
deployTiersHookConfig: deployTiersHookConfig,
|
|
660
|
-
salt: salt == bytes32(0) ? bytes32(0) : keccak256(abi.encode(_msgSender(), salt))
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
// Transfer the hook's ownership to the project.
|
|
664
|
-
JBOwnable(address(hook)).transferOwnershipToProject(projectId);
|
|
665
|
-
|
|
666
|
-
// Convert the 721 ruleset configurations to regular ruleset configurations.
|
|
667
|
-
JBRulesetConfig[] memory rulesetConfigurations =
|
|
668
|
-
_from721Config({launchProjectConfig: queueRulesetsConfig.rulesetConfigurations});
|
|
669
|
-
|
|
670
|
-
// Store the 721 hook per-ruleset and set this contract as data hook.
|
|
671
|
-
// slither-disable-next-line reentrancy-benign
|
|
672
|
-
rulesetConfigurations = _setup721({
|
|
673
|
-
projectId: projectId,
|
|
674
|
-
rulesetConfigurations: rulesetConfigurations,
|
|
675
|
-
hook721: hook,
|
|
676
|
-
customHook: dataHookConfig
|
|
677
|
-
});
|
|
678
|
-
|
|
679
|
-
// Configure the rulesets.
|
|
680
|
-
rulesetId = controller.queueRulesetsOf({
|
|
681
|
-
projectId: projectId, rulesetConfigurations: rulesetConfigurations, memo: queueRulesetsConfig.memo
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
/// @notice Queues new rulesets for a project, using this contract as the data hook.
|
|
686
|
-
/// @param projectId The ID of the project to queue the rulesets for.
|
|
687
|
-
/// @param rulesetConfigurations The rulesets to queue.
|
|
502
|
+
/// @param deploy721Config The 721 hook deployment config (hook config + cash-out flag + salt). If no tiers are
|
|
503
|
+
/// configured, no 721 hook is deployed.
|
|
504
|
+
/// @param rulesetConfigurations The rulesets to queue. Custom data hooks are read from each ruleset's metadata.
|
|
688
505
|
/// @param memo A memo to pass along to the emitted event.
|
|
689
506
|
/// @param controller The controller to use for queuing the rulesets.
|
|
690
507
|
/// @return rulesetId The ID of the newly queued rulesets.
|
|
508
|
+
/// @return hook The 721 tiers hook that was deployed for the project (`address(0)` if none).
|
|
691
509
|
function queueRulesetsOf(
|
|
692
510
|
uint256 projectId,
|
|
693
|
-
|
|
511
|
+
JBOmnichain721Config memory deploy721Config,
|
|
512
|
+
JBRulesetConfig[] memory rulesetConfigurations,
|
|
694
513
|
string calldata memo,
|
|
695
514
|
IJBController controller
|
|
696
515
|
)
|
|
697
516
|
external
|
|
698
517
|
override
|
|
699
|
-
returns (uint256)
|
|
518
|
+
returns (uint256 rulesetId, IJB721TiersHook hook)
|
|
700
519
|
{
|
|
701
520
|
// Enforce permissions.
|
|
702
521
|
_requirePermissionFrom({
|
|
@@ -712,10 +531,23 @@ contract JBOmnichainDeployer is
|
|
|
712
531
|
revert JBOmnichainDeployer_RulesetIdsUnpredictable();
|
|
713
532
|
}
|
|
714
533
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
534
|
+
// Deploy the 721 hook if tiers are configured, otherwise use the non-721 setup path.
|
|
535
|
+
if (deploy721Config.deployTiersHookConfig.tiersConfig.tiers.length > 0) {
|
|
536
|
+
hook = _deploy721Hook(projectId, deploy721Config);
|
|
537
|
+
// slither-disable-next-line reentrancy-benign
|
|
538
|
+
rulesetConfigurations = _setup721({
|
|
539
|
+
projectId: projectId,
|
|
540
|
+
rulesetConfigurations: rulesetConfigurations,
|
|
541
|
+
hook721: hook,
|
|
542
|
+
use721ForCashOut: deploy721Config.useDataHookForCashOut
|
|
543
|
+
});
|
|
544
|
+
} else {
|
|
545
|
+
rulesetConfigurations = _setup({projectId: projectId, rulesetConfigurations: rulesetConfigurations});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Configure the rulesets.
|
|
549
|
+
rulesetId = controller.queueRulesetsOf({
|
|
550
|
+
projectId: projectId, rulesetConfigurations: rulesetConfigurations, memo: memo
|
|
719
551
|
});
|
|
720
552
|
}
|
|
721
553
|
|
|
@@ -728,59 +560,6 @@ contract JBOmnichainDeployer is
|
|
|
728
560
|
return ERC2771Context._contextSuffixLength();
|
|
729
561
|
}
|
|
730
562
|
|
|
731
|
-
/// @notice Converts a 721 ruleset configuration to a regular ruleset configuration.
|
|
732
|
-
/// @dev Sets `metadata.dataHook = address(0)` as a placeholder — actual hooks stored in `_tiered721HookOf` /
|
|
733
|
-
/// `_extraDataHookOf`.
|
|
734
|
-
/// @dev Preserves `metadata.useDataHookForCashOut` from the 721 metadata (used for the 721 hook config).
|
|
735
|
-
/// @param launchProjectConfig The 721 ruleset configuration to convert.
|
|
736
|
-
/// @return rulesetConfigurations The converted ruleset configuration.
|
|
737
|
-
function _from721Config(JBPayDataHookRulesetConfig[] calldata launchProjectConfig)
|
|
738
|
-
internal
|
|
739
|
-
pure
|
|
740
|
-
returns (JBRulesetConfig[] memory rulesetConfigurations)
|
|
741
|
-
{
|
|
742
|
-
rulesetConfigurations = new JBRulesetConfig[](launchProjectConfig.length);
|
|
743
|
-
|
|
744
|
-
for (uint256 i; i < launchProjectConfig.length; i++) {
|
|
745
|
-
JBPayDataHookRulesetMetadata calldata hookMetadata = launchProjectConfig[i].metadata;
|
|
746
|
-
JBRulesetMetadata memory metadata = JBRulesetMetadata({
|
|
747
|
-
// useDataHookForPay is always true — the 721 hook needs it via beforePayRecordedWith.
|
|
748
|
-
useDataHookForPay: true,
|
|
749
|
-
allowSetCustomToken: false,
|
|
750
|
-
// Placeholder — actual hooks stored in _tiered721HookOf / _extraDataHookOf.
|
|
751
|
-
dataHook: address(0),
|
|
752
|
-
// These fields are present in the 721 metadata.
|
|
753
|
-
reservedPercent: hookMetadata.reservedPercent,
|
|
754
|
-
cashOutTaxRate: hookMetadata.cashOutTaxRate,
|
|
755
|
-
baseCurrency: hookMetadata.baseCurrency,
|
|
756
|
-
pausePay: hookMetadata.pausePay,
|
|
757
|
-
pauseCreditTransfers: hookMetadata.pauseCreditTransfers,
|
|
758
|
-
allowOwnerMinting: hookMetadata.allowOwnerMinting,
|
|
759
|
-
allowTerminalMigration: hookMetadata.allowTerminalMigration,
|
|
760
|
-
allowSetController: hookMetadata.allowSetController,
|
|
761
|
-
allowSetTerminals: hookMetadata.allowSetTerminals,
|
|
762
|
-
allowAddAccountingContext: hookMetadata.allowAddAccountingContext,
|
|
763
|
-
allowAddPriceFeed: hookMetadata.allowAddPriceFeed,
|
|
764
|
-
ownerMustSendPayouts: hookMetadata.ownerMustSendPayouts,
|
|
765
|
-
holdFees: hookMetadata.holdFees,
|
|
766
|
-
useTotalSurplusForCashOuts: hookMetadata.useTotalSurplusForCashOuts,
|
|
767
|
-
useDataHookForCashOut: hookMetadata.useDataHookForCashOut,
|
|
768
|
-
metadata: hookMetadata.metadata
|
|
769
|
-
});
|
|
770
|
-
|
|
771
|
-
rulesetConfigurations[i] = JBRulesetConfig({
|
|
772
|
-
mustStartAtOrAfter: launchProjectConfig[i].mustStartAtOrAfter,
|
|
773
|
-
duration: launchProjectConfig[i].duration,
|
|
774
|
-
weight: launchProjectConfig[i].weight,
|
|
775
|
-
weightCutPercent: launchProjectConfig[i].weightCutPercent,
|
|
776
|
-
approvalHook: launchProjectConfig[i].approvalHook,
|
|
777
|
-
metadata: metadata,
|
|
778
|
-
splitGroups: launchProjectConfig[i].splitGroups,
|
|
779
|
-
fundAccessLimitGroups: launchProjectConfig[i].fundAccessLimitGroups
|
|
780
|
-
});
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
563
|
/// @notice The calldata. Preferred to use over `msg.data`.
|
|
785
564
|
/// @return calldata The `msg.data` of this call.
|
|
786
565
|
function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
|
|
@@ -793,6 +572,30 @@ contract JBOmnichainDeployer is
|
|
|
793
572
|
return ERC2771Context._msgSender();
|
|
794
573
|
}
|
|
795
574
|
|
|
575
|
+
/// @notice Deploys a 721 tiers hook and transfers its ownership to the project.
|
|
576
|
+
/// @param projectId The ID of the project to deploy the hook for.
|
|
577
|
+
/// @param config The 721 hook deployment config (hook config + cash-out flag + salt).
|
|
578
|
+
/// @return hook The deployed 721 tiers hook.
|
|
579
|
+
function _deploy721Hook(
|
|
580
|
+
uint256 projectId,
|
|
581
|
+
JBOmnichain721Config memory config
|
|
582
|
+
)
|
|
583
|
+
internal
|
|
584
|
+
returns (IJB721TiersHook hook)
|
|
585
|
+
{
|
|
586
|
+
// Deploy the hook.
|
|
587
|
+
// Note: the salt includes `_msgSender()` for replay protection. Cross-chain deterministic
|
|
588
|
+
// address matching requires using the same sender address on each chain.
|
|
589
|
+
hook = HOOK_DEPLOYER.deployHookFor({
|
|
590
|
+
projectId: projectId,
|
|
591
|
+
deployTiersHookConfig: config.deployTiersHookConfig,
|
|
592
|
+
salt: config.salt == bytes32(0) ? bytes32(0) : keccak256(abi.encode(_msgSender(), config.salt))
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
// Transfer the hook's ownership to the project.
|
|
596
|
+
JBOwnable(address(hook)).transferOwnershipToProject(projectId);
|
|
597
|
+
}
|
|
598
|
+
|
|
796
599
|
/// @notice Sets up a project's rulesets (non-721 path).
|
|
797
600
|
/// @dev Reads the data hook from each ruleset's metadata and stores it in `_extraDataHookOf`.
|
|
798
601
|
/// @dev Stores data hook configs keyed by predicted ruleset IDs (`block.timestamp + i`). This prediction is correct
|
|
@@ -833,34 +636,38 @@ contract JBOmnichainDeployer is
|
|
|
833
636
|
}
|
|
834
637
|
|
|
835
638
|
/// @notice Sets up a project's rulesets for 721 projects.
|
|
836
|
-
/// @dev Stores the 721 hook in `_tiered721HookOf` per-ruleset and
|
|
639
|
+
/// @dev Stores the 721 hook in `_tiered721HookOf` per-ruleset and any custom hook (from metadata) in
|
|
640
|
+
/// `_extraDataHookOf`.
|
|
837
641
|
/// @param projectId The ID of the project to set up.
|
|
838
|
-
/// @param rulesetConfigurations The rulesets to set up
|
|
642
|
+
/// @param rulesetConfigurations The rulesets to set up.
|
|
839
643
|
/// @param hook721 The 721 tiers hook.
|
|
840
|
-
/// @param
|
|
644
|
+
/// @param use721ForCashOut Whether the 721 hook should handle cash outs.
|
|
841
645
|
/// @return rulesetConfigurations The rulesets that were set up.
|
|
842
646
|
function _setup721(
|
|
843
647
|
uint256 projectId,
|
|
844
648
|
JBRulesetConfig[] memory rulesetConfigurations,
|
|
845
649
|
IJB721TiersHook hook721,
|
|
846
|
-
|
|
650
|
+
bool use721ForCashOut
|
|
847
651
|
)
|
|
848
652
|
internal
|
|
849
653
|
returns (JBRulesetConfig[] memory)
|
|
850
654
|
{
|
|
851
|
-
// Validate the custom hook isn't this contract.
|
|
852
|
-
if (address(customHook.dataHook) == address(this)) revert JBOmnichainDeployer_InvalidHook();
|
|
853
|
-
|
|
854
655
|
for (uint256 i; i < rulesetConfigurations.length; i++) {
|
|
656
|
+
// Validate no self-reference.
|
|
657
|
+
if (rulesetConfigurations[i].metadata.dataHook == address(this)) revert JBOmnichainDeployer_InvalidHook();
|
|
658
|
+
|
|
855
659
|
// Store the 721 hook config per-ruleset.
|
|
856
660
|
// slither-disable-next-line reentrancy-benign
|
|
857
|
-
_tiered721HookOf[projectId][block.timestamp + i] =
|
|
858
|
-
hook: hook721, useDataHookForCashOut:
|
|
859
|
-
});
|
|
661
|
+
_tiered721HookOf[projectId][block.timestamp + i] =
|
|
662
|
+
JBTiered721HookConfig({hook: hook721, useDataHookForCashOut: use721ForCashOut});
|
|
860
663
|
|
|
861
|
-
// Store
|
|
862
|
-
if (
|
|
863
|
-
_extraDataHookOf[projectId][block.timestamp + i] =
|
|
664
|
+
// Store custom hook from metadata (same as _setup).
|
|
665
|
+
if (rulesetConfigurations[i].metadata.dataHook != address(0)) {
|
|
666
|
+
_extraDataHookOf[projectId][block.timestamp + i] = JBDeployerHookConfig({
|
|
667
|
+
dataHook: IJBRulesetDataHook(rulesetConfigurations[i].metadata.dataHook),
|
|
668
|
+
useDataHookForPay: rulesetConfigurations[i].metadata.useDataHookForPay,
|
|
669
|
+
useDataHookForCashOut: rulesetConfigurations[i].metadata.useDataHookForCashOut
|
|
670
|
+
});
|
|
864
671
|
}
|
|
865
672
|
|
|
866
673
|
// Set this contract as the data hook, force both pay and cashout through this wrapper.
|