@towns-protocol/contracts 1.0.1 → 1.0.2

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.
Files changed (32) hide show
  1. package/package.json +2 -2
  2. package/scripts/deployments/diamonds/DeployL2Registrar.s.sol +0 -2
  3. package/scripts/deployments/diamonds/DeploySpaceFactory.s.sol +0 -12
  4. package/scripts/deployments/facets/DeployArchitect.s.sol +1 -3
  5. package/scripts/deployments/facets/DeployCreateSpace.s.sol +2 -1
  6. package/scripts/deployments/facets/DeployNodeRegistry.s.sol +4 -1
  7. package/scripts/deployments/utils/DeployDomainFeeHook.s.sol +78 -0
  8. package/scripts/interactions/InteractAlphaPost.s.sol +0 -7
  9. package/scripts/interactions/InteractBaseAlpha.s.sol +1 -14
  10. package/scripts/interactions/InteractDomainFee.s.sol +62 -0
  11. package/scripts/interactions/InteractSetStreamDistributionBalancingAdvantage.s.sol +42 -0
  12. package/scripts/interactions/InteractSetStreamDistributionRequiredOperators.s.sol +32 -0
  13. package/scripts/interactions/helpers/RiverConfigValues.sol +6 -0
  14. package/src/factory/facets/architect/Architect.sol +48 -29
  15. package/src/factory/facets/architect/IArchitect.sol +2 -21
  16. package/src/factory/facets/architect/ImplementationStorage.sol +12 -20
  17. package/src/factory/facets/create/CreateSpace.sol +5 -0
  18. package/src/factory/facets/create/CreateSpaceBase.sol +32 -8
  19. package/src/factory/facets/create/ICreateSpace.sol +5 -0
  20. package/src/factory/facets/fee/FeeManagerFacet.sol +10 -0
  21. package/src/river/registry/facets/node/INodeRegistry.sol +25 -0
  22. package/src/river/registry/facets/node/NodeRegistry.sol +53 -2
  23. package/src/river/registry/libraries/RegistryStorage.sol +5 -0
  24. package/src/spaces/facets/proxy/SpaceProxyInitializer.sol +6 -8
  25. package/src/spaces/facets/xchain/SpaceEntitlementGated.sol +9 -0
  26. package/scripts/bytecode-diff/README.md +0 -182
  27. package/scripts/deployments/facets/DeploySpaceFactoryInit.s.sol +0 -33
  28. package/scripts/deployments/utils/DeploySpaceProxyInitializer.s.sol +0 -28
  29. package/scripts/readme.md +0 -289
  30. package/src/diamond/readme.md +0 -50
  31. package/src/factory/SpaceFactoryInit.sol +0 -17
  32. package/src/factory/facets/architect/ArchitectBase.sol +0 -95
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@towns-protocol/contracts",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "scripts": {
5
5
  "clean": "forge clean",
6
6
  "compile": "forge build",
@@ -34,7 +34,7 @@
34
34
  "@layerzerolabs/oapp-evm": "^0.3.2",
35
35
  "@openzeppelin/merkle-tree": "^1.0.8",
36
36
  "@prb/test": "^0.6.4",
37
- "@towns-protocol/prettier-config": "workspace:^",
37
+ "@towns-protocol/prettier-config": "^0.0.455",
38
38
  "@wagmi/cli": "^2.2.0",
39
39
  "forge-std": "github:foundry-rs/forge-std#v1.12.0",
40
40
  "prettier": "^3.5.3",
@@ -159,8 +159,6 @@ contract DeployL2Registrar is IDiamondInitHelper, DiamondHelper, Deployer {
159
159
  }
160
160
 
161
161
  function __deploy(address deployer) internal override returns (address) {
162
- require(REGISTRY != address(0), "DeployL2Registrar: registry not set");
163
-
164
162
  addImmutableCuts(deployer);
165
163
 
166
164
  Diamond.InitParams memory initDiamondCut = diamondInitParams(deployer);
@@ -15,7 +15,6 @@ import {DeployProxyManager} from "@towns-protocol/diamond/scripts/deployments/ut
15
15
  import {DeployFeatureManager} from "../facets/DeployFeatureManager.s.sol";
16
16
  import {DeployMetadata} from "../facets/DeployMetadata.s.sol";
17
17
  import {DeployPricingModules} from "../facets/DeployPricingModules.s.sol";
18
- import {DeploySpaceFactoryInit} from "../facets/DeploySpaceFactoryInit.s.sol";
19
18
  import {DeployArchitect} from "../facets/DeployArchitect.s.sol";
20
19
  import {DeployCreateSpace} from "../facets/DeployCreateSpace.s.sol";
21
20
  import {DeployImplementationRegistry} from "../facets/DeployImplementationRegistry.s.sol";
@@ -64,10 +63,6 @@ contract DeploySpaceFactory is IDiamondInitHelper, DiamondHelper, Deployer {
64
63
  address public fixedPricing;
65
64
  address public mockDelegationRegistry;
66
65
 
67
- // init
68
- address public spaceFactoryInit;
69
- bytes public spaceFactoryInitData;
70
-
71
66
  function versionName() public pure override returns (string memory) {
72
67
  return "spaceFactory";
73
68
  }
@@ -150,8 +145,6 @@ contract DeploySpaceFactory is IDiamondInitHelper, DiamondHelper, Deployer {
150
145
  facetHelper.add("PartnerRegistry");
151
146
  facetHelper.add("FeatureManagerFacet");
152
147
  facetHelper.add("FeeManagerFacet");
153
- facetHelper.add("SpaceProxyInitializer");
154
- facetHelper.add("SpaceFactoryInit");
155
148
 
156
149
  if (isAnvil()) {
157
150
  facetHelper.add("MockDelegationRegistry");
@@ -277,11 +270,6 @@ contract DeploySpaceFactory is IDiamondInitHelper, DiamondHelper, Deployer {
277
270
  DeployFeeManager.makeInitData(deployer)
278
271
  );
279
272
 
280
- address spaceProxyInitializer = facetHelper.getDeployedAddress("SpaceProxyInitializer");
281
- spaceFactoryInit = facetHelper.getDeployedAddress("SpaceFactoryInit");
282
- spaceFactoryInitData = DeploySpaceFactoryInit.makeInitData(spaceProxyInitializer);
283
- addInit(spaceFactoryInit, spaceFactoryInitData);
284
-
285
273
  address multiInit = facetHelper.getDeployedAddress("MultiInit");
286
274
 
287
275
  return
@@ -13,13 +13,11 @@ import {Architect} from "src/factory/facets/architect/Architect.sol";
13
13
 
14
14
  library DeployArchitect {
15
15
  function selectors() internal pure returns (bytes4[] memory _selectors) {
16
- _selectors = new bytes4[](6);
16
+ _selectors = new bytes4[](4);
17
17
  _selectors[0] = IArchitect.getSpaceByTokenId.selector;
18
18
  _selectors[1] = IArchitect.getTokenIdBySpace.selector;
19
19
  _selectors[2] = IArchitect.setSpaceArchitectImplementations.selector;
20
20
  _selectors[3] = IArchitect.getSpaceArchitectImplementations.selector;
21
- _selectors[4] = IArchitect.setProxyInitializer.selector;
22
- _selectors[5] = IArchitect.getProxyInitializer.selector;
23
21
  }
24
22
 
25
23
  function makeCut(
@@ -12,7 +12,7 @@ import {CreateSpaceFacet} from "src/factory/facets/create/CreateSpace.sol";
12
12
 
13
13
  library DeployCreateSpace {
14
14
  function selectors() internal pure returns (bytes4[] memory _selectors) {
15
- _selectors = new bytes4[](5);
15
+ _selectors = new bytes4[](6);
16
16
  // createSpace(SpaceInfo) - Basic space creation with SpaceInfo struct
17
17
  _selectors[0] = 0xf822028d;
18
18
  // createSpaceWithPrepay(CreateSpace) - Space creation with prepay (new format)
@@ -23,6 +23,7 @@ library DeployCreateSpace {
23
23
  _selectors[3] = CreateSpaceFacet.createSpaceV2.selector;
24
24
  // createSpace(Action, bytes) - Unified entry point with action dispatch
25
25
  _selectors[4] = bytes4(keccak256("createSpace(uint8,bytes)"));
26
+ _selectors[5] = CreateSpaceFacet.getProxyInitializer.selector;
26
27
  }
27
28
 
28
29
  function makeCut(
@@ -12,7 +12,7 @@ import {NodeRegistry} from "src/river/registry/facets/node/NodeRegistry.sol";
12
12
 
13
13
  library DeployNodeRegistry {
14
14
  function selectors() internal pure returns (bytes4[] memory res) {
15
- res = new bytes4[](9);
15
+ res = new bytes4[](12);
16
16
  res[0] = NodeRegistry.isNode.selector;
17
17
  res[1] = NodeRegistry.registerNode.selector;
18
18
  res[2] = NodeRegistry.removeNode.selector;
@@ -22,6 +22,9 @@ library DeployNodeRegistry {
22
22
  res[6] = NodeRegistry.getNodeCount.selector;
23
23
  res[7] = NodeRegistry.getAllNodeAddresses.selector;
24
24
  res[8] = NodeRegistry.getAllNodes.selector;
25
+ res[9] = NodeRegistry.backfillPermanentIndices.selector;
26
+ res[10] = NodeRegistry.setNodeCometBftPubKey.selector;
27
+ res[11] = NodeRegistry.getLastNodeIndex.selector;
25
28
  }
26
29
 
27
30
  function makeCut(
@@ -0,0 +1,78 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+ import {Deployer} from "../../common/Deployer.s.sol";
10
+ import {DomainFeeHook} from "src/domains/hooks/DomainFeeHook.sol";
11
+
12
+ contract DeployDomainFeeHook is Deployer {
13
+ /// @dev Default price for domain registration (5 USDC with 6 decimals)
14
+ uint256 internal constant DEFAULT_PRICE = 5e6;
15
+
16
+ address internal owner;
17
+ address internal feeManager;
18
+ uint256 internal defaultPrice;
19
+
20
+ function versionName() public pure override returns (string memory) {
21
+ return "utils/domainFeeHook";
22
+ }
23
+
24
+ /// @notice Set the owner address
25
+ /// @param owner_ The owner address for the DomainFeeHook
26
+ function setOwner(address owner_) external {
27
+ owner = owner_;
28
+ }
29
+
30
+ /// @notice Set the fee manager address
31
+ /// @param feeManager_ The fee manager address authorized to call onChargeFee
32
+ function setFeeManager(address feeManager_) external {
33
+ feeManager = feeManager_;
34
+ }
35
+
36
+ /// @notice Set the default price for registrations
37
+ /// @param defaultPrice_ The default price in USDC (6 decimals)
38
+ function setDefaultPrice(uint256 defaultPrice_) external {
39
+ defaultPrice = defaultPrice_;
40
+ }
41
+
42
+ /// @notice Set all deployment parameters at once
43
+ /// @param owner_ The owner address
44
+ /// @param feeManager_ The fee manager address
45
+ /// @param defaultPrice_ The default price for registrations
46
+ function setParams(address owner_, address feeManager_, uint256 defaultPrice_) external {
47
+ owner = owner_;
48
+ feeManager = feeManager_;
49
+ defaultPrice = defaultPrice_;
50
+ }
51
+
52
+ function __deploy(address deployer) internal override returns (address) {
53
+ address ownerAddr = _getOwner(deployer);
54
+ address feeManagerAddr = _getFeeManager();
55
+ uint256 price = _getDefaultPrice();
56
+
57
+ require(ownerAddr != address(0), "DeployDomainFeeHook: owner not set");
58
+ require(feeManagerAddr != address(0), "DeployDomainFeeHook: feeManager not set");
59
+
60
+ vm.broadcast(deployer);
61
+ return address(new DomainFeeHook(ownerAddr, feeManagerAddr, price));
62
+ }
63
+
64
+ function _getOwner(address deployer) internal view returns (address) {
65
+ return owner == address(0) ? deployer : owner;
66
+ }
67
+
68
+ function _getFeeManager() internal returns (address) {
69
+ if (feeManager != address(0)) return feeManager;
70
+
71
+ // Try to get from existing deployments (spaceFactory acts as fee manager)
72
+ return getDeployment("spaceFactory");
73
+ }
74
+
75
+ function _getDefaultPrice() internal view returns (uint256) {
76
+ return defaultPrice == 0 ? DEFAULT_PRICE : defaultPrice;
77
+ }
78
+ }
@@ -2,10 +2,7 @@
2
2
  pragma solidity ^0.8.23;
3
3
 
4
4
  // interfaces
5
- import {IArchitect} from "src/factory/facets/architect/IArchitect.sol";
6
-
7
5
  import {IPricingModules} from "src/factory/facets/architect/pricing/IPricingModules.sol";
8
- import {ISpaceProxyInitializer} from "src/spaces/facets/proxy/ISpaceProxyInitializer.sol";
9
6
 
10
7
  // deployment
11
8
  import {DeployTieredLogPricingV3} from "scripts/deployments/utils/DeployTieredLogPricingV3.s.sol";
@@ -19,13 +16,9 @@ contract InteractAlphaPost is Interaction {
19
16
  function __interact(address deployer) internal override {
20
17
  address spaceFactory = getDeployment("spaceFactory");
21
18
 
22
- vm.setEnv("OVERRIDE_DEPLOYMENTS", "1");
23
- vm.broadcast(deployer);
24
- address spaceProxyInitializer = deployCode("SpaceProxyInitializer.sol", "");
25
19
  address tieredLogPricing = deployTieredLogPricingV3.deploy(deployer);
26
20
 
27
21
  vm.startBroadcast(deployer);
28
- IArchitect(spaceFactory).setProxyInitializer(ISpaceProxyInitializer(spaceProxyInitializer));
29
22
  IPricingModules(spaceFactory).addPricingModule(tieredLogPricing);
30
23
  vm.stopBroadcast();
31
24
  }
@@ -37,20 +37,7 @@ contract InteractBaseAlpha is AlphaHelper {
37
37
 
38
38
  executeDiamondCutsWithLogging(deployer, space, "Space", deploySpace);
39
39
  executeDiamondCutsWithLogging(deployer, spaceOwner, "SpaceOwner", deploySpaceOwner);
40
-
41
- deploySpaceFactory.diamondInitParams(deployer);
42
- address spaceFactoryInit = deploySpaceFactory.spaceFactoryInit();
43
- bytes memory initData = deploySpaceFactory.spaceFactoryInitData();
44
- deploySpaceFactory.clearCuts();
45
-
46
- executeDiamondCutsWithLogging(
47
- deployer,
48
- spaceFactory,
49
- "SpaceFactory",
50
- deploySpaceFactory,
51
- spaceFactoryInit,
52
- initData
53
- );
40
+ executeDiamondCutsWithLogging(deployer, spaceFactory, "SpaceFactory", deploySpaceFactory);
54
41
 
55
42
  executeDiamondCutsWithLogging(deployer, baseRegistry, "BaseRegistry", deployBaseRegistry);
56
43
  executeDiamondCutsWithLogging(deployer, riverAirdrop, "RiverAirdrop", deployRiverAirdrop);
@@ -0,0 +1,62 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IFeeManager} from "src/factory/facets/fee/IFeeManager.sol";
6
+ import {IPlatformRequirements} from "src/factory/facets/platform/requirements/IPlatformRequirements.sol";
7
+
8
+ // libraries
9
+ import {FeeTypesLib} from "src/factory/facets/fee/FeeTypesLib.sol";
10
+ import {FeeCalculationMethod} from "src/factory/facets/fee/FeeManagerStorage.sol";
11
+ import {console} from "forge-std/console.sol";
12
+
13
+ // contracts
14
+ import {Interaction} from "../common/Interaction.s.sol";
15
+
16
+ /// @title InteractDomainFee
17
+ /// @notice Interaction script to configure domain registration fee and hook
18
+ contract InteractDomainFee is Interaction {
19
+ function __interact(address deployer) internal override {
20
+ address spaceFactory = getDeployment("spaceFactory");
21
+ address domainFeeHook = getDeployment("utils/domainFeeHook");
22
+
23
+ console.log("SpaceFactory Diamond:", spaceFactory);
24
+ console.log("Domain Fee Hook:", domainFeeHook);
25
+
26
+ // Get fee recipient from PlatformRequirementsFacet
27
+ address feeRecipient = IPlatformRequirements(spaceFactory).getFeeRecipient();
28
+ console.log("Fee Recipient:", feeRecipient);
29
+
30
+ // Set fee configuration for domain registration
31
+ // The hook will override the fee calculation, so we use FIXED with 0 values
32
+ console.log("\n=== Setting Fee Config for Domain Registration ===");
33
+ vm.broadcast(deployer);
34
+ IFeeManager(spaceFactory).setFeeConfig(
35
+ FeeTypesLib.DOMAIN_REGISTRATION,
36
+ feeRecipient, // recipient from PlatformRequirements
37
+ FeeCalculationMethod.FIXED, // method (hook overrides the calculation)
38
+ 0, // bps (not used for FIXED)
39
+ 0, // fixedFee (hook overrides)
40
+ true // enabled
41
+ );
42
+ console.log("Fee config set for DOMAIN_REGISTRATION");
43
+ console.log(" Recipient:", feeRecipient);
44
+ console.log(" Method: FIXED (hook overrides)");
45
+ console.log(" Enabled: true");
46
+
47
+ // Set the domain fee hook
48
+ console.log("\n=== Setting Domain Fee Hook ===");
49
+ vm.broadcast(deployer);
50
+ IFeeManager(spaceFactory).setFeeHook(FeeTypesLib.DOMAIN_REGISTRATION, domainFeeHook);
51
+ console.log("Fee hook set for DOMAIN_REGISTRATION:", domainFeeHook);
52
+
53
+ // Verify configuration
54
+ console.log("\n=== Verifying Configuration ===");
55
+ address configuredHook = IFeeManager(spaceFactory).getFeeHook(
56
+ FeeTypesLib.DOMAIN_REGISTRATION
57
+ );
58
+ console.log("Configured hook:", configuredHook);
59
+
60
+ console.log("\n=== Domain Fee Configuration Complete ===");
61
+ }
62
+ }
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.24;
3
+
4
+ // interfaces
5
+ import {IRiverConfig} from "src/river/registry/facets/config/IRiverConfig.sol";
6
+
7
+ // libraries
8
+ import {RiverConfigValues} from "scripts/interactions/helpers/RiverConfigValues.sol";
9
+
10
+ // contracts
11
+ import {Interaction} from "scripts/common/Interaction.s.sol";
12
+
13
+ /// @notice Sets the min and max balancing advantage for required operator node selection.
14
+ /// @dev Values are in basis points (e.g., 500 = 5%, 750 = 7.5%).
15
+ /// These settings control load balancing when selecting among required operator nodes:
16
+ /// - MinBalancingAdvantage: Minimum advantage for less-loaded nodes (default: 500 = 5%)
17
+ /// - MaxBalancingAdvantage: Maximum advantage for less-loaded nodes (default: 750 = 7.5%)
18
+ contract InteractSetStreamDistributionBalancingAdvantage is Interaction {
19
+ function __interact(address deployer) internal override {
20
+ address riverRegistry = getDeployment("riverRegistry");
21
+
22
+ // Values in basis points (100 = 1%, 500 = 5%, 750 = 7.5%)
23
+ uint64 minBalancingAdvantage = 500; // 5%
24
+ uint64 maxBalancingAdvantage = 750; // 7.5%
25
+
26
+ vm.startBroadcast(deployer);
27
+
28
+ IRiverConfig(riverRegistry).setConfiguration(
29
+ RiverConfigValues.STREAM_DISTRIBUTION_MIN_BALANCING_ADVANTAGE,
30
+ 0, // blockNumber: 0 means effective immediately
31
+ abi.encode(minBalancingAdvantage)
32
+ );
33
+
34
+ IRiverConfig(riverRegistry).setConfiguration(
35
+ RiverConfigValues.STREAM_DISTRIBUTION_MAX_BALANCING_ADVANTAGE,
36
+ 0, // blockNumber: 0 means effective immediately
37
+ abi.encode(maxBalancingAdvantage)
38
+ );
39
+
40
+ vm.stopBroadcast();
41
+ }
42
+ }
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.24;
3
+
4
+ // interfaces
5
+ import {IRiverConfig} from "src/river/registry/facets/config/IRiverConfig.sol";
6
+
7
+ // libraries
8
+ import {RiverConfigValues} from "scripts/interactions/helpers/RiverConfigValues.sol";
9
+
10
+ // contracts
11
+ import {Interaction} from "scripts/common/Interaction.s.sol";
12
+
13
+ /// @notice Sets the required operators for stream placement.
14
+ /// @dev When placing a stream, at least one node from a required operator must be selected
15
+ /// if any required operator has operational nodes available.
16
+ contract InteractSetStreamDistributionRequiredOperators is Interaction {
17
+ function __interact(address deployer) internal override {
18
+ address riverRegistry = getDeployment("riverRegistry");
19
+
20
+ // Configure the required operator addresses here
21
+ address[] memory requiredOperators = new address[](1);
22
+ requiredOperators[0] = address(0); // Replace with actual operator address
23
+
24
+ vm.startBroadcast(deployer);
25
+ IRiverConfig(riverRegistry).setConfiguration(
26
+ RiverConfigValues.STREAM_DISTRIBUTION_REQUIRED_OPERATORS,
27
+ 0, // blockNumber: 0 means effective immediately
28
+ abi.encode(requiredOperators)
29
+ );
30
+ vm.stopBroadcast();
31
+ }
32
+ }
@@ -24,4 +24,10 @@ library RiverConfigValues {
24
24
  bytes32 public constant STREAM_TRIM_ACTIVATION_FACTOR =
25
25
  keccak256("stream.trimactivationfactor");
26
26
  bytes32 public constant STREAM_TRIM_BY_STREAM_ID = keccak256("stream.trimbystreamid");
27
+ bytes32 public constant STREAM_DISTRIBUTION_REQUIRED_OPERATORS =
28
+ keccak256("stream.distribution.requiredoperators");
29
+ bytes32 public constant STREAM_DISTRIBUTION_MIN_BALANCING_ADVANTAGE =
30
+ keccak256("stream.distribution.minbalancingadvantage");
31
+ bytes32 public constant STREAM_DISTRIBUTION_MAX_BALANCING_ADVANTAGE =
32
+ keccak256("stream.distribution.maxbalancingadvantage");
27
33
  }
@@ -2,25 +2,30 @@
2
2
  pragma solidity ^0.8.23;
3
3
 
4
4
  // interfaces
5
- import {IArchitect} from "src/factory/facets/architect/IArchitect.sol";
6
- import {IRuleEntitlement} from "src/spaces/entitlements/rule/IRuleEntitlement.sol";
7
- import {IRuleEntitlementV2} from "src/spaces/entitlements/rule/IRuleEntitlement.sol";
8
-
9
- import {IUserEntitlement} from "src/spaces/entitlements/user/IUserEntitlement.sol";
10
- import {ISpaceOwner} from "src/spaces/facets/owner/ISpaceOwner.sol";
11
- import {ISpaceProxyInitializer} from "src/spaces/facets/proxy/ISpaceProxyInitializer.sol";
5
+ import {IRuleEntitlement} from "../../../spaces/entitlements/rule/IRuleEntitlement.sol";
6
+ import {IRuleEntitlementV2} from "../../../spaces/entitlements/rule/IRuleEntitlement.sol";
7
+ import {IUserEntitlement} from "../../../spaces/entitlements/user/IUserEntitlement.sol";
8
+ import {ISpaceOwner} from "../../../spaces/facets/owner/ISpaceOwner.sol";
9
+ import {IArchitect, IArchitectBase} from "./IArchitect.sol";
12
10
 
13
11
  // libraries
12
+ import {ArchitectStorage} from "./ArchitectStorage.sol";
13
+ import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
14
+ import {ImplementationStorage} from "./ImplementationStorage.sol";
14
15
 
15
16
  // contracts
16
- import {ArchitectBase} from "./ArchitectBase.sol";
17
-
18
17
  import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
19
18
  import {OwnableBase} from "@towns-protocol/diamond/src/facets/ownable/OwnableBase.sol";
20
19
  import {PausableBase} from "@towns-protocol/diamond/src/facets/pausable/PausableBase.sol";
21
20
  import {ReentrancyGuard} from "solady/utils/ReentrancyGuard.sol";
22
21
 
23
- contract Architect is IArchitect, ArchitectBase, OwnableBase, PausableBase, ReentrancyGuard, Facet {
22
+ contract Architect is IArchitect, OwnableBase, PausableBase, ReentrancyGuard, Facet {
23
+ using CustomRevert for bytes4;
24
+
25
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
26
+ /* INITIALIZATION */
27
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
28
+
24
29
  function __Architect_init(
25
30
  ISpaceOwner ownerImplementation,
26
31
  IUserEntitlement userEntitlementImplementation,
@@ -35,23 +40,23 @@ contract Architect is IArchitect, ArchitectBase, OwnableBase, PausableBase, Reen
35
40
  );
36
41
  }
37
42
 
38
- // =============================================================
39
- // Space
40
- // =============================================================
43
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
44
+ /* REGISTRY */
45
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
41
46
 
42
47
  /// @inheritdoc IArchitect
43
48
  function getSpaceByTokenId(uint256 tokenId) external view returns (address) {
44
- return _getSpaceByTokenId(tokenId);
49
+ return ArchitectStorage.layout().spaceByTokenId[tokenId];
45
50
  }
46
51
 
47
52
  /// @inheritdoc IArchitect
48
53
  function getTokenIdBySpace(address space) external view returns (uint256) {
49
- return _getTokenIdBySpace(space);
54
+ return ArchitectStorage.layout().tokenIdBySpace[space];
50
55
  }
51
56
 
52
- // =============================================================
53
- // Implementations
54
- // =============================================================
57
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
58
+ /* IMPLEMENTATIONS */
59
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
55
60
 
56
61
  /// @inheritdoc IArchitect
57
62
  function setSpaceArchitectImplementations(
@@ -79,20 +84,34 @@ contract Architect is IArchitect, ArchitectBase, OwnableBase, PausableBase, Reen
79
84
  IRuleEntitlement legacyRuleEntitlement
80
85
  )
81
86
  {
82
- return _getImplementations();
87
+ ImplementationStorage.Layout storage $ = ImplementationStorage.getStorage();
88
+ return ($.spaceOwnerToken, $.userEntitlement, $.ruleEntitlement, $.legacyRuleEntitlement);
83
89
  }
84
90
 
85
- // =============================================================
86
- // Proxy Initializer
87
- // =============================================================
91
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
92
+ /* INTERNAL */
93
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
88
94
 
89
- /// @inheritdoc IArchitect
90
- function getProxyInitializer() external view returns (ISpaceProxyInitializer) {
91
- return _getProxyInitializer();
92
- }
95
+ function _setImplementations(
96
+ ISpaceOwner spaceOwnerToken,
97
+ IUserEntitlement userEntitlement,
98
+ IRuleEntitlementV2 ruleEntitlement,
99
+ IRuleEntitlement legacyRuleEntitlement
100
+ ) private {
101
+ if (address(spaceOwnerToken).code.length == 0) {
102
+ Architect__NotContract.selector.revertWith();
103
+ }
104
+ if (address(userEntitlement).code.length == 0) {
105
+ Architect__NotContract.selector.revertWith();
106
+ }
107
+ if (address(ruleEntitlement).code.length == 0) {
108
+ Architect__NotContract.selector.revertWith();
109
+ }
93
110
 
94
- /// @inheritdoc IArchitect
95
- function setProxyInitializer(ISpaceProxyInitializer proxyInitializer) external onlyOwner {
96
- _setProxyInitializer(proxyInitializer);
111
+ ImplementationStorage.Layout storage $ = ImplementationStorage.getStorage();
112
+ $.spaceOwnerToken = spaceOwnerToken;
113
+ $.userEntitlement = userEntitlement;
114
+ $.ruleEntitlement = ruleEntitlement;
115
+ $.legacyRuleEntitlement = legacyRuleEntitlement;
97
116
  }
98
117
  }
@@ -6,7 +6,6 @@ import {IRuleEntitlement, IRuleEntitlementV2} from "../../../spaces/entitlements
6
6
  import {IUserEntitlement} from "../../../spaces/entitlements/user/IUserEntitlement.sol";
7
7
  import {IMembershipBase} from "../../../spaces/facets/membership/IMembership.sol";
8
8
  import {ISpaceOwner} from "../../../spaces/facets/owner/ISpaceOwner.sol";
9
- import {ISpaceProxyInitializer} from "../../../spaces/facets/proxy/ISpaceProxyInitializer.sol";
10
9
 
11
10
  interface IArchitectBase {
12
11
  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
@@ -92,19 +91,14 @@ interface IArchitectBase {
92
91
  /* ERRORS */
93
92
  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
94
93
 
95
- error Architect__InvalidStringLength();
96
- error Architect__InvalidNetworkId();
97
- error Architect__InvalidAddress();
98
94
  error Architect__NotContract();
99
95
  error Architect__InvalidPricingModule();
100
96
  error Architect__UnexpectedETH();
101
-
102
- event Architect__ProxyInitializerSet(address indexed proxyInitializer);
103
97
  }
104
98
 
105
99
  interface IArchitect is IArchitectBase {
106
100
  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
107
- /* Registry */
101
+ /* REGISTRY */
108
102
  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
109
103
 
110
104
  function getSpaceByTokenId(uint256 tokenId) external view returns (address space);
@@ -112,7 +106,7 @@ interface IArchitect is IArchitectBase {
112
106
  function getTokenIdBySpace(address space) external view returns (uint256);
113
107
 
114
108
  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
115
- /* Implementations */
109
+ /* IMPLEMENTATIONS */
116
110
  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
117
111
 
118
112
  function setSpaceArchitectImplementations(
@@ -131,17 +125,4 @@ interface IArchitect is IArchitectBase {
131
125
  IRuleEntitlementV2 ruleEntitlementImplementation,
132
126
  IRuleEntitlement legacyRuleEntitlement
133
127
  );
134
-
135
- /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
136
- /* Proxy Initializer */
137
- /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
138
-
139
- /// @notice Retrieves the current proxy initializer
140
- /// @return The address of the current ISpaceProxyInitializer contract
141
- function getProxyInitializer() external view returns (ISpaceProxyInitializer);
142
-
143
- /// @notice Sets a new proxy initializer
144
- /// @param proxyInitializer The address of the new ISpaceProxyInitializer contract to be set
145
- /// @dev This function should only be callable by the contract owner or authorized roles
146
- function setProxyInitializer(ISpaceProxyInitializer proxyInitializer) external;
147
128
  }
@@ -2,23 +2,16 @@
2
2
  pragma solidity ^0.8.23;
3
3
 
4
4
  // interfaces
5
-
6
- import {IEntitlementChecker} from "src/base/registry/facets/checker/IEntitlementChecker.sol";
7
- import {IWalletLink} from "src/factory/facets/wallet-link/IWalletLink.sol";
8
- import {IRuleEntitlement} from "src/spaces/entitlements/rule/IRuleEntitlement.sol";
9
- import {IRuleEntitlementV2} from "src/spaces/entitlements/rule/IRuleEntitlement.sol";
10
- import {IUserEntitlement} from "src/spaces/entitlements/user/IUserEntitlement.sol";
11
- import {ISpaceOwner} from "src/spaces/facets/owner/ISpaceOwner.sol";
12
- import {ISpaceProxyInitializer} from "src/spaces/facets/proxy/ISpaceProxyInitializer.sol";
13
- // libraries
14
-
15
- // contracts
5
+ import {IEntitlementChecker} from "../../../base/registry/facets/checker/IEntitlementChecker.sol";
6
+ import {IRuleEntitlement, IRuleEntitlementV2} from "../../../spaces/entitlements/rule/IRuleEntitlement.sol";
7
+ import {IUserEntitlement} from "../../../spaces/entitlements/user/IUserEntitlement.sol";
8
+ import {ISpaceOwner} from "../../../spaces/facets/owner/ISpaceOwner.sol";
9
+ import {IWalletLink} from "../wallet-link/IWalletLink.sol";
16
10
 
17
11
  library ImplementationStorage {
18
12
  // keccak256(abi.encode(uint256(keccak256("spaces.facets.architect.implementation.storage")) -
19
- // 1))
20
- // & ~bytes32(uint256(0xff))
21
- bytes32 internal constant SLOT_POSITION =
13
+ // 1)) & ~bytes32(uint256(0xff))
14
+ bytes32 internal constant STORAGE_SLOT =
22
15
  0x9e34afa7b4d27d347d25d9d9dab4f1a106fa081382e6c4243e834d093e787d00;
23
16
 
24
17
  struct Layout {
@@ -28,15 +21,14 @@ library ImplementationStorage {
28
21
  IWalletLink walletLink;
29
22
  IEntitlementChecker entitlementChecker;
30
23
  IRuleEntitlement legacyRuleEntitlement;
31
- ISpaceProxyInitializer proxyInitializer;
24
+ /// @dev Deprecated: SpaceProxyInitializer is now deployed via CREATE2 in CreateSpaceBase.
25
+ /// Slot preserved for storage layout compatibility.
26
+ address _proxyInitializer;
32
27
  }
33
28
 
34
- function layout() internal pure returns (Layout storage ds) {
35
- bytes32 position = SLOT_POSITION;
36
-
37
- // solhint-disable-next-line no-inline-assembly
29
+ function getStorage() internal pure returns (Layout storage $) {
38
30
  assembly {
39
- ds.slot := position
31
+ $.slot := STORAGE_SLOT
40
32
  }
41
33
  }
42
34
  }
@@ -99,4 +99,9 @@ contract CreateSpaceFacet is ICreateSpace, PausableBase, ReentrancyGuard, Create
99
99
  SpaceOptions memory spaceOptions = SpaceOptions({to: msg.sender});
100
100
  return _createSpaceWithPrepayFromLegacy(spaceInfo, spaceOptions);
101
101
  }
102
+
103
+ /// @inheritdoc ICreateSpace
104
+ function getProxyInitializer() external view returns (address) {
105
+ return _getProxyInitializer();
106
+ }
102
107
  }