@towns-protocol/contracts 0.0.377 → 0.0.379

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@towns-protocol/contracts",
3
- "version": "0.0.377",
3
+ "version": "0.0.379",
4
4
  "packageManager": "yarn@3.8.0",
5
5
  "scripts": {
6
6
  "build-types": "bash scripts/build-contract-types.sh",
@@ -35,7 +35,7 @@
35
35
  "@layerzerolabs/oapp-evm": "^0.3.2",
36
36
  "@openzeppelin/merkle-tree": "^1.0.8",
37
37
  "@prb/test": "^0.6.4",
38
- "@towns-protocol/prettier-config": "^0.0.377",
38
+ "@towns-protocol/prettier-config": "^0.0.379",
39
39
  "@typechain/ethers-v5": "^11.1.2",
40
40
  "@wagmi/cli": "^2.2.0",
41
41
  "forge-std": "github:foundry-rs/forge-std#v1.10.0",
@@ -57,5 +57,5 @@
57
57
  "publishConfig": {
58
58
  "access": "public"
59
59
  },
60
- "gitHead": "a289c507ab3ae080d0b07e9f881743223580fdf4"
60
+ "gitHead": "2f050be64e496b13fa8a67053bfdd0605180aa45"
61
61
  }
@@ -14,6 +14,7 @@ import {DeployMetadata} from "../facets/DeployMetadata.s.sol";
14
14
  import {DeployAppRegistryFacet} from "../facets/DeployAppRegistryFacet.s.sol";
15
15
  import {DeployUpgradeableBeacon} from "../facets/DeployUpgradeableBeacon.s.sol";
16
16
  import {DeployAppInstallerFacet} from "../facets/DeployAppInstallerFacet.s.sol";
17
+ import {DeployAppFactoryFacet} from "../facets/DeployAppFactoryFacet.s.sol";
17
18
  import {DeploySpaceFactory} from "../diamonds/DeploySpaceFactory.s.sol";
18
19
 
19
20
  // contracts
@@ -46,6 +47,7 @@ contract DeployAppRegistry is IDiamondInitHelper, DiamondHelper, Deployer {
46
47
  facetHelper.add("DiamondLoupeFacet");
47
48
  facetHelper.add("IntrospectionFacet");
48
49
  facetHelper.add("OwnableFacet");
50
+ facetHelper.add("MetadataFacet");
49
51
 
50
52
  // Deploy the first batch of facets
51
53
  facetHelper.deployBatch(deployer);
@@ -78,28 +80,28 @@ contract DeployAppRegistry is IDiamondInitHelper, DiamondHelper, Deployer {
78
80
  facet,
79
81
  DeployOwnable.makeInitData(deployer)
80
82
  );
83
+
84
+ facet = facetHelper.getDeployedAddress("MetadataFacet");
85
+ addFacet(
86
+ makeCut(facet, FacetCutAction.Add, DeployMetadata.selectors()),
87
+ facet,
88
+ DeployMetadata.makeInitData(bytes32("AppRegistry"), "")
89
+ );
81
90
  }
82
91
 
83
92
  function diamondInitParams(address deployer) public returns (Diamond.InitParams memory) {
84
93
  // Queue up feature facets for batch deployment
85
94
  facetHelper.add("MultiInit");
86
- facetHelper.add("MetadataFacet");
87
95
  facetHelper.add("UpgradeableBeaconFacet");
88
96
  facetHelper.add("AppRegistryFacet");
89
97
  facetHelper.add("AppInstallerFacet");
98
+ facetHelper.add("AppFactoryFacet");
90
99
  facetHelper.add("SimpleApp");
91
100
 
92
101
  facetHelper.deployBatch(deployer);
93
102
 
94
- address facet = facetHelper.getDeployedAddress("MetadataFacet");
95
- addFacet(
96
- makeCut(facet, FacetCutAction.Add, DeployMetadata.selectors()),
97
- facet,
98
- DeployMetadata.makeInitData(bytes32("AppRegistry"), "")
99
- );
100
-
101
103
  address simpleApp = facetHelper.getDeployedAddress("SimpleApp");
102
- facet = facetHelper.getDeployedAddress("UpgradeableBeaconFacet");
104
+ address facet = facetHelper.getDeployedAddress("UpgradeableBeaconFacet");
103
105
 
104
106
  addFacet(
105
107
  makeCut(facet, FacetCutAction.Add, DeployUpgradeableBeacon.selectors()),
@@ -121,6 +123,13 @@ contract DeployAppRegistry is IDiamondInitHelper, DiamondHelper, Deployer {
121
123
  DeployAppInstallerFacet.makeInitData()
122
124
  );
123
125
 
126
+ facet = facetHelper.getDeployedAddress("AppFactoryFacet");
127
+ addFacet(
128
+ makeCut(facet, FacetCutAction.Add, DeployAppFactoryFacet.selectors()),
129
+ facet,
130
+ DeployAppFactoryFacet.makeInitData()
131
+ );
132
+
124
133
  address multiInit = facetHelper.getDeployedAddress("MultiInit");
125
134
 
126
135
  return
@@ -153,6 +162,9 @@ contract DeployAppRegistry is IDiamondInitHelper, DiamondHelper, Deployer {
153
162
  if (facetName.eq("AppInstallerFacet")) {
154
163
  addCut(makeCut(facet, FacetCutAction.Add, DeployAppInstallerFacet.selectors()));
155
164
  }
165
+ if (facetName.eq("AppFactoryFacet")) {
166
+ addCut(makeCut(facet, FacetCutAction.Add, DeployAppFactoryFacet.selectors()));
167
+ }
156
168
  }
157
169
 
158
170
  return baseFacets();
@@ -0,0 +1,45 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ //interfaces
5
+ import {IDiamond} from "@towns-protocol/diamond/src/IDiamond.sol";
6
+
7
+ //libraries
8
+
9
+ //contracts
10
+ import {LibDeploy} from "@towns-protocol/diamond/src/utils/LibDeploy.sol";
11
+ import {AppFactoryFacet} from "src/apps/facets/factory/AppFactoryFacet.sol";
12
+ import {DynamicArrayLib} from "solady/utils/DynamicArrayLib.sol";
13
+
14
+ library DeployAppFactoryFacet {
15
+ using DynamicArrayLib for DynamicArrayLib.DynamicArray;
16
+
17
+ function selectors() internal pure returns (bytes4[] memory res) {
18
+ DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(1);
19
+ arr.p(AppFactoryFacet.createApp.selector);
20
+ bytes32[] memory selectors_ = arr.asBytes32Array();
21
+ assembly ("memory-safe") {
22
+ res := selectors_
23
+ }
24
+ }
25
+
26
+ function makeCut(
27
+ address facetAddress,
28
+ IDiamond.FacetCutAction action
29
+ ) internal pure returns (IDiamond.FacetCut memory) {
30
+ return
31
+ IDiamond.FacetCut({
32
+ action: action,
33
+ facetAddress: facetAddress,
34
+ functionSelectors: selectors()
35
+ });
36
+ }
37
+
38
+ function makeInitData() internal pure returns (bytes memory) {
39
+ return abi.encodeCall(AppFactoryFacet.__AppFactory_init, ());
40
+ }
41
+
42
+ function deploy() internal returns (address) {
43
+ return LibDeploy.deployCode("AppFactoryFacet.sol", "");
44
+ }
45
+ }
@@ -16,14 +16,13 @@ library DeployAppRegistryFacet {
16
16
  using DynamicArrayLib for DynamicArrayLib.DynamicArray;
17
17
 
18
18
  function selectors() internal pure returns (bytes4[] memory res) {
19
- DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(14);
19
+ DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(13);
20
20
  arr.p(AppRegistryFacet.getAppSchema.selector);
21
21
  arr.p(AppRegistryFacet.getAppSchemaId.selector);
22
22
  arr.p(AppRegistryFacet.getAppById.selector);
23
23
  arr.p(AppRegistryFacet.getLatestAppId.selector);
24
24
  arr.p(AppRegistryFacet.registerApp.selector);
25
25
  arr.p(AppRegistryFacet.removeApp.selector);
26
- arr.p(AppRegistryFacet.createApp.selector);
27
26
  arr.p(AppRegistryFacet.upgradeApp.selector);
28
27
  arr.p(AppRegistryFacet.getAppPrice.selector);
29
28
  arr.p(AppRegistryFacet.getAppDuration.selector);
@@ -2,14 +2,14 @@
2
2
  pragma solidity ^0.8.23;
3
3
 
4
4
  //interfaces
5
- import {IAppRegistry} from "src/apps/facets/registry/IAppRegistry.sol";
5
+ import {IAppFactory} from "src/apps/facets/factory/IAppFactory.sol";
6
6
 
7
7
  //contracts
8
8
  import {Interaction} from "../common/Interaction.s.sol";
9
9
  import {SimpleApp} from "src/apps/helpers/SimpleApp.sol";
10
- import {IAppRegistryBase} from "src/apps/facets/registry/IAppRegistry.sol";
10
+ import {IAppFactoryBase} from "src/apps/facets/factory/IAppFactory.sol";
11
11
 
12
- contract InteractRegisterApp is Interaction, IAppRegistryBase {
12
+ contract InteractRegisterApp is Interaction, IAppFactoryBase {
13
13
  function __interact(address deployer) internal override {
14
14
  address appRegistry = getDeployment("appRegistry");
15
15
 
@@ -32,7 +32,7 @@ contract InteractRegisterApp is Interaction, IAppRegistryBase {
32
32
  });
33
33
 
34
34
  vm.broadcast(deployer);
35
- (address app, bytes32 appId) = IAppRegistry(appRegistry).createApp(appData);
35
+ (address app, bytes32 appId) = IAppFactory(appRegistry).createApp(appData);
36
36
 
37
37
  saveApp("SimpleApp", appId, address(app));
38
38
  }
@@ -0,0 +1,52 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+ import {IAppFactory} from "./IAppFactory.sol";
6
+ import {ISimpleApp} from "../../helpers/ISimpleApp.sol";
7
+ import {ITownsApp} from "../../ITownsApp.sol";
8
+
9
+ // libraries
10
+ import {LibClone} from "solady/utils/LibClone.sol";
11
+ import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
12
+
13
+ // contracts
14
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
15
+ import {AppRegistryBase} from "../registry/AppRegistryBase.sol";
16
+ import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
17
+
18
+ /// @title AppInstallerFacet
19
+ /// @author Towns Protocol
20
+ /// @notice Facet for installing apps to spaces
21
+ contract AppFactoryFacet is IAppFactory, AppRegistryBase, ReentrancyGuardTransient, Facet {
22
+ using CustomRevert for bytes4;
23
+
24
+ function __AppFactory_init() external onlyInitializing {
25
+ _addInterface(type(IAppFactory).interfaceId);
26
+ }
27
+
28
+ /// @notice Create an upgradeable simple app contract
29
+ /// @param params The parameters of the app
30
+ function createApp(
31
+ AppParams calldata params
32
+ ) external payable nonReentrant returns (address app, bytes32 appId) {
33
+ if (bytes(params.name).length == 0) AppFactory__InvalidAppName.selector.revertWith();
34
+ if (params.permissions.length == 0) AppFactory__InvalidArrayInput.selector.revertWith();
35
+ if (params.client == address(0)) AppFactory__InvalidAddressInput.selector.revertWith();
36
+
37
+ uint48 duration = _validateDuration(params.accessDuration);
38
+
39
+ app = LibClone.deployERC1967BeaconProxy(address(this));
40
+ ISimpleApp(app).initialize(
41
+ msg.sender,
42
+ params.name,
43
+ params.permissions,
44
+ params.installPrice,
45
+ duration,
46
+ params.client
47
+ );
48
+
49
+ appId = _registerApp(ITownsApp(app), params.client);
50
+ emit AppCreated(app, appId);
51
+ }
52
+ }
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+
10
+ interface IAppFactoryBase {
11
+ struct AppParams {
12
+ string name;
13
+ bytes32[] permissions;
14
+ address client;
15
+ uint256 installPrice;
16
+ uint48 accessDuration;
17
+ }
18
+
19
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
20
+ /* ERRORS */
21
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
22
+ error AppFactory__InvalidAppName();
23
+ error AppFactory__InvalidArrayInput();
24
+ error AppFactory__InvalidAddressInput();
25
+
26
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
27
+
28
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
29
+ /* EVENTS */
30
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
31
+ event AppCreated(address indexed app, bytes32 indexed uid);
32
+ }
33
+
34
+ interface IAppFactory is IAppFactoryBase {
35
+ /// @notice Create a new app
36
+ /// @param params The parameters of the app
37
+ /// @return app The app address
38
+ /// @return appId The attestation UID of the registered app
39
+ function createApp(
40
+ AppParams calldata params
41
+ ) external payable returns (address app, bytes32 appId);
42
+ }
@@ -123,33 +123,6 @@ abstract contract AppRegistryBase is IAppRegistryBase, SchemaBase, AttestationBa
123
123
  return AppRegistryStorage.getLayout().client[client].app;
124
124
  }
125
125
 
126
- /// @notice Creates a new app with the specified parameters
127
- /// @param params The parameters for creating the app
128
- /// @return app The address of the created app
129
- /// @return version The version ID of the registered app
130
- /// @dev Validates inputs, deploys app contract, and registers it
131
- function _createApp(AppParams calldata params) internal returns (address app, bytes32 version) {
132
- // Validate basic parameters
133
- if (bytes(params.name).length == 0) InvalidAppName.selector.revertWith();
134
- if (params.permissions.length == 0) InvalidArrayInput.selector.revertWith();
135
- if (params.client == address(0)) InvalidAddressInput.selector.revertWith();
136
-
137
- uint48 duration = _validateDuration(params.accessDuration);
138
-
139
- app = LibClone.deployERC1967BeaconProxy(address(this));
140
- ISimpleApp(app).initialize(
141
- msg.sender,
142
- params.name,
143
- params.permissions,
144
- params.installPrice,
145
- duration,
146
- params.client
147
- );
148
-
149
- version = _registerApp(ITownsApp(app), params.client);
150
- emit AppCreated(app, version);
151
- }
152
-
153
126
  function _upgradeApp(
154
127
  ITownsApp app,
155
128
  address client,
@@ -4,7 +4,6 @@ pragma solidity ^0.8.23;
4
4
  // interfaces
5
5
  import {IAppRegistry} from "./IAppRegistry.sol";
6
6
  import {ISchemaResolver} from "@ethereum-attestation-service/eas-contracts/resolver/ISchemaResolver.sol";
7
- import {IAppAccount} from "../../../spaces/facets/account/IAppAccount.sol";
8
7
  import {ITownsApp} from "../../ITownsApp.sol";
9
8
 
10
9
  // types
@@ -55,14 +54,6 @@ contract AppRegistryFacet is IAppRegistry, AppRegistryBase, OwnableBase, Reentra
55
54
  /* App Functions */
56
55
  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
57
56
 
58
- /// @notice Create an upgradeable simple app contract
59
- /// @param params The parameters of the app
60
- function createApp(
61
- AppParams calldata params
62
- ) external payable nonReentrant returns (address app, bytes32 appId) {
63
- return _createApp(params);
64
- }
65
-
66
57
  /// @notice Register a new app with permissions
67
58
  /// @param app The app address to register
68
59
  /// @param client The client address that will make calls from this app
@@ -40,10 +40,10 @@ library AppRegistryStorage {
40
40
  0xe1abd3beb055e0136b3111c2c34ff6e869f8c0d7540225f8056528d6eb12b500;
41
41
 
42
42
  /// @notice Returns the storage layout for the module registry
43
- /// @return l The storage layout struct
44
- function getLayout() internal pure returns (Layout storage l) {
43
+ /// @return $ The storage layout struct
44
+ function getLayout() internal pure returns (Layout storage $) {
45
45
  assembly {
46
- l.slot := STORAGE_SLOT
46
+ $.slot := STORAGE_SLOT
47
47
  }
48
48
  }
49
49
  }
@@ -11,14 +11,6 @@ import {Attestation} from "@ethereum-attestation-service/eas-contracts/Common.so
11
11
  import {ExecutionManifest} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol";
12
12
 
13
13
  interface IAppRegistryBase {
14
- struct AppParams {
15
- string name;
16
- bytes32[] permissions;
17
- address client;
18
- uint256 installPrice;
19
- uint48 accessDuration;
20
- }
21
-
22
14
  struct App {
23
15
  bytes32 appId;
24
16
  address module;
@@ -58,7 +50,6 @@ interface IAppRegistryBase {
58
50
  event AppUpdated(address indexed app, bytes32 uid);
59
51
  event AppBanned(address indexed app, bytes32 uid);
60
52
  event AppSchemaSet(bytes32 uid);
61
- event AppCreated(address indexed app, bytes32 uid);
62
53
  event AppInstalled(address indexed app, address indexed account, bytes32 indexed appId);
63
54
  event AppUninstalled(address indexed app, address indexed account, bytes32 indexed appId);
64
55
  event AppRenewed(address indexed app, address indexed account, bytes32 indexed appId);
@@ -111,14 +102,6 @@ interface IAppRegistry is IAppRegistryBase {
111
102
  /// @return isBanned True if the app is banned, false otherwise
112
103
  function isAppBanned(address app) external view returns (bool);
113
104
 
114
- /// @notice Create a new app
115
- /// @param params The parameters of the app
116
- /// @return app The app address
117
- /// @return appId The attestation UID of the registered app
118
- function createApp(
119
- AppParams calldata params
120
- ) external payable returns (address app, bytes32 appId);
121
-
122
105
  /// @notice Register a new app with permissions
123
106
  /// @param app The app address to register
124
107
  /// @param client The client contract address that will use this app