@towns-protocol/contracts 0.0.440 → 0.0.442

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 (30) hide show
  1. package/package.json +3 -3
  2. package/scripts/deployments/diamonds/DeployAccountModules.s.sol +188 -0
  3. package/scripts/deployments/diamonds/DeploySpace.s.sol +0 -7
  4. package/scripts/deployments/facets/DeployAccountHubFacet.s.sol +47 -0
  5. package/scripts/deployments/facets/DeployAccountTippingFacet.s.sol +37 -0
  6. package/scripts/deployments/facets/DeployAppManagerFacet.s.sol +40 -0
  7. package/scripts/interactions/InteractBaseAlpha.s.sol +3 -0
  8. package/src/account/facets/app/AppManagerFacet.sol +68 -0
  9. package/src/account/facets/app/AppManagerMod.sol +321 -0
  10. package/src/account/facets/hub/AccountHubFacet.sol +226 -0
  11. package/src/account/facets/hub/AccountHubMod.sol +136 -0
  12. package/src/account/facets/hub/IAccountHub.sol +25 -0
  13. package/src/account/facets/tipping/AccountTippingFacet.sol +72 -0
  14. package/src/account/facets/tipping/AccountTippingMod.sol +144 -0
  15. package/src/apps/facets/registry/AppRegistryBase.sol +4 -2
  16. package/src/apps/facets/registry/IAppRegistry.sol +1 -1
  17. package/src/factory/facets/architect/IArchitect.sol +1 -0
  18. package/src/factory/facets/create/CreateSpaceBase.sol +2 -9
  19. package/src/spaces/facets/account/AppAccountStorage.sol +0 -1
  20. package/src/spaces/facets/membership/IMembership.sol +0 -16
  21. package/src/spaces/facets/membership/join/MembershipJoin.sol +6 -15
  22. package/src/spaces/facets/tipping/ITipping.sol +14 -19
  23. package/src/spaces/facets/tipping/TippingBase.sol +0 -1
  24. package/src/spaces/facets/xchain/SpaceEntitlementGated.sol +0 -2
  25. package/scripts/deployments/facets/DeployPrepayFacet.s.sol +0 -31
  26. package/scripts/interactions/InteractPrepay.s.sol +0 -30
  27. package/src/spaces/facets/prepay/IPrepay.sol +0 -44
  28. package/src/spaces/facets/prepay/PrepayBase.sol +0 -27
  29. package/src/spaces/facets/prepay/PrepayFacet.sol +0 -65
  30. package/src/spaces/facets/prepay/PrepayStorage.sol +0 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@towns-protocol/contracts",
3
- "version": "0.0.440",
3
+ "version": "0.0.442",
4
4
  "scripts": {
5
5
  "clean": "forge clean",
6
6
  "compile": "forge build",
@@ -33,7 +33,7 @@
33
33
  "@layerzerolabs/oapp-evm": "^0.3.2",
34
34
  "@openzeppelin/merkle-tree": "^1.0.8",
35
35
  "@prb/test": "^0.6.4",
36
- "@towns-protocol/prettier-config": "^0.0.440",
36
+ "@towns-protocol/prettier-config": "^0.0.442",
37
37
  "@wagmi/cli": "^2.2.0",
38
38
  "forge-std": "github:foundry-rs/forge-std#v1.10.0",
39
39
  "prettier": "^3.5.3",
@@ -50,5 +50,5 @@
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "gitHead": "7c25c92bebcb924258f283120f670a7517895807"
53
+ "gitHead": "d2e07ef0deb899067d0d1a47e30c4edd5bb22547"
54
54
  }
@@ -0,0 +1,188 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IDiamondInitHelper} from "./IDiamondInitHelper.sol";
6
+
7
+ // libraries
8
+ import {DeployDiamondCut} from "@towns-protocol/diamond/scripts/deployments/facets/DeployDiamondCut.sol";
9
+ import {DeployDiamondLoupe} from "@towns-protocol/diamond/scripts/deployments/facets/DeployDiamondLoupe.sol";
10
+ import {DeployIntrospection} from "@towns-protocol/diamond/scripts/deployments/facets/DeployIntrospection.sol";
11
+ import {DeployOwnable} from "@towns-protocol/diamond/scripts/deployments/facets/DeployOwnable.sol";
12
+ import {DeployMetadata} from "../facets/DeployMetadata.s.sol";
13
+ import {DeployAccountHubFacet} from "../facets/DeployAccountHubFacet.s.sol";
14
+ import {DeployAppManagerFacet} from "../facets/DeployAppManagerFacet.s.sol";
15
+ import {DeployAccountTippingFacet} from "../facets/DeployAccountTippingFacet.s.sol";
16
+ import {DeploySpaceFactory} from "./DeploySpaceFactory.s.sol";
17
+ import {DeployAppRegistry} from "./DeployAppRegistry.s.sol";
18
+ import {LibString} from "solady/utils/LibString.sol";
19
+
20
+ // contracts
21
+ import {Diamond} from "@towns-protocol/diamond/src/Diamond.sol";
22
+ import {MultiInit} from "@towns-protocol/diamond/src/initializers/MultiInit.sol";
23
+ import {DiamondHelper} from "@towns-protocol/diamond/scripts/common/helpers/DiamondHelper.s.sol";
24
+
25
+ // deployers
26
+ import {DeployFacet} from "../../common/DeployFacet.s.sol";
27
+ import {Deployer} from "../../common/Deployer.s.sol";
28
+
29
+ contract DeployAccountModules is IDiamondInitHelper, DiamondHelper, Deployer {
30
+ using LibString for string;
31
+
32
+ DeployFacet private facetHelper = new DeployFacet();
33
+ DeploySpaceFactory private deploySpaceFactory = new DeploySpaceFactory();
34
+ DeployAppRegistry private deployAppRegistry = new DeployAppRegistry();
35
+
36
+ address public spaceFactory;
37
+ address public appRegistry;
38
+
39
+ bytes32 internal constant METADATA_NAME = bytes32("AccountModules");
40
+
41
+ function versionName() public pure override returns (string memory) {
42
+ return "accountModules";
43
+ }
44
+
45
+ function setDependencies(address spaceFactory_, address appRegistry_) external {
46
+ spaceFactory = spaceFactory_;
47
+ appRegistry = appRegistry_;
48
+ }
49
+
50
+ function diamondInitHelper(
51
+ address deployer,
52
+ string[] memory facetNames
53
+ ) external override returns (FacetCut[] memory) {
54
+ for (uint256 i; i < facetNames.length; ++i) {
55
+ facetHelper.add(facetNames[i]);
56
+ }
57
+
58
+ facetHelper.deployBatch(deployer);
59
+
60
+ for (uint256 i; i < facetNames.length; ++i) {
61
+ string memory facetName = facetNames[i];
62
+ address facet = facetHelper.getDeployedAddress(facetName);
63
+
64
+ if (facetName.eq("AccountHubFacet")) {
65
+ addCut(makeCut(facet, FacetCutAction.Add, DeployAccountHubFacet.selectors()));
66
+ }
67
+ if (facetName.eq("AppManagerFacet")) {
68
+ addCut(makeCut(facet, FacetCutAction.Add, DeployAppManagerFacet.selectors()));
69
+ }
70
+ if (facetName.eq("AccountTippingFacet")) {
71
+ addCut(makeCut(facet, FacetCutAction.Add, DeployAccountTippingFacet.selectors()));
72
+ }
73
+ }
74
+
75
+ return baseFacets();
76
+ }
77
+
78
+ function diamondInitParams(address deployer) public returns (Diamond.InitParams memory) {
79
+ // Queue up feature facets for batch deployment
80
+ facetHelper.add("MultiInit");
81
+ facetHelper.add("MetadataFacet");
82
+ facetHelper.add("AccountHubFacet");
83
+ facetHelper.add("AppManagerFacet");
84
+ facetHelper.add("AccountTippingFacet");
85
+
86
+ facetHelper.deployBatch(deployer);
87
+
88
+ // Add feature facets
89
+ address facet = facetHelper.getDeployedAddress("MetadataFacet");
90
+ addFacet(
91
+ makeCut(facet, FacetCutAction.Add, DeployMetadata.selectors()),
92
+ facet,
93
+ DeployMetadata.makeInitData(METADATA_NAME, "")
94
+ );
95
+
96
+ facet = facetHelper.getDeployedAddress("AccountHubFacet");
97
+ addFacet(
98
+ makeCut(facet, FacetCutAction.Add, DeployAccountHubFacet.selectors()),
99
+ facet,
100
+ DeployAccountHubFacet.makeInitData(spaceFactory, appRegistry)
101
+ );
102
+
103
+ facet = facetHelper.getDeployedAddress("AppManagerFacet");
104
+ addFacet(
105
+ makeCut(facet, FacetCutAction.Add, DeployAppManagerFacet.selectors()),
106
+ facet,
107
+ DeployAppManagerFacet.makeInitData()
108
+ );
109
+
110
+ facet = facetHelper.getDeployedAddress("AccountTippingFacet");
111
+ addFacet(
112
+ makeCut(facet, FacetCutAction.Add, DeployAccountTippingFacet.selectors()),
113
+ facet,
114
+ DeployAccountTippingFacet.makeInitData()
115
+ );
116
+
117
+ address multiInit = facetHelper.getDeployedAddress("MultiInit");
118
+
119
+ return
120
+ Diamond.InitParams({
121
+ baseFacets: baseFacets(),
122
+ init: multiInit,
123
+ initData: abi.encodeCall(MultiInit.multiInit, (_initAddresses, _initDatas))
124
+ });
125
+ }
126
+
127
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
128
+ /* Internal */
129
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
130
+
131
+ function _resolveDependencies(address deployer) internal {
132
+ spaceFactory = spaceFactory == address(0)
133
+ ? deploySpaceFactory.deploy(deployer)
134
+ : spaceFactory;
135
+ appRegistry = appRegistry == address(0) ? deployAppRegistry.deploy(deployer) : appRegistry;
136
+ }
137
+
138
+ function _coreFacets(address deployer) internal {
139
+ // Deploy dependencies
140
+ _resolveDependencies(deployer);
141
+
142
+ // Queue up all core facets for batch deployment
143
+ facetHelper.add("DiamondCutFacet");
144
+ facetHelper.add("DiamondLoupeFacet");
145
+ facetHelper.add("IntrospectionFacet");
146
+ facetHelper.add("OwnableFacet");
147
+
148
+ // Get predicted addresses
149
+ address facet = facetHelper.predictAddress("DiamondCutFacet");
150
+ addFacet(
151
+ makeCut(facet, FacetCutAction.Add, DeployDiamondCut.selectors()),
152
+ facet,
153
+ DeployDiamondCut.makeInitData()
154
+ );
155
+
156
+ facet = facetHelper.predictAddress("DiamondLoupeFacet");
157
+ addFacet(
158
+ makeCut(facet, FacetCutAction.Add, DeployDiamondLoupe.selectors()),
159
+ facet,
160
+ DeployDiamondLoupe.makeInitData()
161
+ );
162
+
163
+ facet = facetHelper.predictAddress("IntrospectionFacet");
164
+ addFacet(
165
+ makeCut(facet, FacetCutAction.Add, DeployIntrospection.selectors()),
166
+ facet,
167
+ DeployIntrospection.makeInitData()
168
+ );
169
+
170
+ facet = facetHelper.predictAddress("OwnableFacet");
171
+ addFacet(
172
+ makeCut(facet, FacetCutAction.Add, DeployOwnable.selectors()),
173
+ facet,
174
+ DeployOwnable.makeInitData(deployer)
175
+ );
176
+ }
177
+
178
+ function __deploy(address deployer) internal override returns (address) {
179
+ _coreFacets(deployer);
180
+
181
+ Diamond.InitParams memory initDiamondCut = diamondInitParams(deployer);
182
+
183
+ vm.broadcast(deployer);
184
+ Diamond diamond = new Diamond(initDiamondCut);
185
+
186
+ return address(diamond);
187
+ }
188
+ }
@@ -20,7 +20,6 @@ import {DeployEntitlementsManager} from "../facets/DeployEntitlementsManager.s.s
20
20
  import {DeployMembership} from "../facets/DeployMembership.s.sol";
21
21
  import {DeployMembershipMetadata} from "../facets/DeployMembershipMetadata.s.sol";
22
22
  import {DeployMembershipToken} from "../facets/DeployMembershipToken.s.sol";
23
- import {DeployPrepayFacet} from "../facets/DeployPrepayFacet.s.sol";
24
23
  import {DeployReferrals} from "../facets/DeployReferrals.s.sol";
25
24
  import {DeployReviewFacet} from "../facets/DeployReviewFacet.s.sol";
26
25
  import {DeployRoles} from "../facets/DeployRoles.s.sol";
@@ -112,7 +111,6 @@ contract DeploySpace is IDiamondInitHelper, DiamondHelper, Deployer {
112
111
  facetHelper.add("Roles");
113
112
  facetHelper.add("Channels");
114
113
  facetHelper.add("TokenPausableFacet");
115
- facetHelper.add("PrepayFacet");
116
114
  facetHelper.add("ReferralsFacet");
117
115
  facetHelper.add("ReviewFacet");
118
116
 
@@ -164,9 +162,6 @@ contract DeploySpace is IDiamondInitHelper, DiamondHelper, Deployer {
164
162
  facet = facetHelper.getDeployedAddress("TokenPausableFacet");
165
163
  addCut(makeCut(facet, FacetCutAction.Add, DeployTokenPausable.selectors()));
166
164
 
167
- facet = facetHelper.getDeployedAddress("PrepayFacet");
168
- addCut(makeCut(facet, FacetCutAction.Add, DeployPrepayFacet.selectors()));
169
-
170
165
  facet = facetHelper.getDeployedAddress("ReferralsFacet");
171
166
  addCut(makeCut(facet, FacetCutAction.Add, DeployReferrals.selectors()));
172
167
 
@@ -247,8 +242,6 @@ contract DeploySpace is IDiamondInitHelper, DiamondHelper, Deployer {
247
242
  addCut(makeCut(facet, FacetCutAction.Add, DeployChannels.selectors()));
248
243
  } else if (facetName.eq("TokenPausableFacet")) {
249
244
  addCut(makeCut(facet, FacetCutAction.Add, DeployTokenPausable.selectors()));
250
- } else if (facetName.eq("PrepayFacet")) {
251
- addCut(makeCut(facet, FacetCutAction.Add, DeployPrepayFacet.selectors()));
252
245
  } else if (facetName.eq("ReferralsFacet")) {
253
246
  addCut(makeCut(facet, FacetCutAction.Add, DeployReferrals.selectors()));
254
247
  } else if (facetName.eq("ReviewFacet")) {
@@ -0,0 +1,47 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+
6
+ // contracts
7
+ import {LibDeploy} from "@towns-protocol/diamond/src/utils/LibDeploy.sol";
8
+ import {AccountHubFacet} from "src/account/facets/hub/AccountHubFacet.sol";
9
+ import {DynamicArrayLib} from "solady/utils/DynamicArrayLib.sol";
10
+
11
+ library DeployAccountHubFacet {
12
+ using DynamicArrayLib for DynamicArrayLib.DynamicArray;
13
+
14
+ function selectors() internal pure returns (bytes4[] memory res) {
15
+ DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(11);
16
+
17
+ // ERC-6900 functions
18
+ arr.p(AccountHubFacet.moduleId.selector);
19
+ arr.p(AccountHubFacet.onInstall.selector);
20
+ arr.p(AccountHubFacet.onUninstall.selector);
21
+ arr.p(AccountHubFacet.preExecutionHook.selector);
22
+ arr.p(AccountHubFacet.postExecutionHook.selector);
23
+ arr.p(AccountHubFacet.executionManifest.selector);
24
+
25
+ // External functions
26
+ arr.p(AccountHubFacet.setSpaceFactory.selector);
27
+ arr.p(AccountHubFacet.setAppRegistry.selector);
28
+ arr.p(AccountHubFacet.getSpaceFactory.selector);
29
+ arr.p(AccountHubFacet.getAppRegistry.selector);
30
+ arr.p(AccountHubFacet.isInstalled.selector);
31
+ bytes32[] memory selectors_ = arr.asBytes32Array();
32
+ assembly ("memory-safe") {
33
+ res := selectors_
34
+ }
35
+ }
36
+
37
+ function makeInitData(
38
+ address spaceFactory,
39
+ address appRegistry
40
+ ) internal pure returns (bytes memory) {
41
+ return abi.encodeCall(AccountHubFacet.__AccountHubFacet_init, (spaceFactory, appRegistry));
42
+ }
43
+
44
+ function deploy() internal returns (address) {
45
+ return LibDeploy.deployCode("AccountHubFacet.sol", "");
46
+ }
47
+ }
@@ -0,0 +1,37 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // contracts
5
+ import {LibDeploy} from "@towns-protocol/diamond/src/utils/LibDeploy.sol";
6
+ import {AccountTippingFacet} from "src/account/facets/tipping/AccountTippingFacet.sol";
7
+ import {DynamicArrayLib} from "solady/utils/DynamicArrayLib.sol";
8
+
9
+ library DeployAccountTippingFacet {
10
+ using DynamicArrayLib for DynamicArrayLib.DynamicArray;
11
+
12
+ function selectors() internal pure returns (bytes4[] memory res) {
13
+ DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(8);
14
+
15
+ arr.p(AccountTippingFacet.sendTip.selector);
16
+ arr.p(AccountTippingFacet.tip.selector);
17
+ arr.p(AccountTippingFacet.tipsByWalletAndCurrency.selector);
18
+ arr.p(AccountTippingFacet.tipCountByWalletAndCurrency.selector);
19
+ arr.p(AccountTippingFacet.tipsByCurrencyAndTokenId.selector);
20
+ arr.p(AccountTippingFacet.tippingCurrencies.selector);
21
+ arr.p(AccountTippingFacet.totalTipsByCurrency.selector);
22
+ arr.p(AccountTippingFacet.tipAmountByCurrency.selector);
23
+
24
+ bytes32[] memory selectors_ = arr.asBytes32Array();
25
+ assembly ("memory-safe") {
26
+ res := selectors_
27
+ }
28
+ }
29
+
30
+ function makeInitData() internal pure returns (bytes memory) {
31
+ return abi.encodeCall(AccountTippingFacet.__AccountTippingFacet_init, ());
32
+ }
33
+
34
+ function deploy() internal returns (address) {
35
+ return LibDeploy.deployCode("AccountTippingFacet.sol", "");
36
+ }
37
+ }
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // contracts
5
+ import {LibDeploy} from "@towns-protocol/diamond/src/utils/LibDeploy.sol";
6
+ import {AppManagerFacet} from "src/account/facets/app/AppManagerFacet.sol";
7
+ import {DynamicArrayLib} from "solady/utils/DynamicArrayLib.sol";
8
+
9
+ library DeployAppManagerFacet {
10
+ using DynamicArrayLib for DynamicArrayLib.DynamicArray;
11
+
12
+ function selectors() internal pure returns (bytes4[] memory res) {
13
+ DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(11);
14
+
15
+ arr.p(AppManagerFacet.onInstallApp.selector);
16
+ arr.p(AppManagerFacet.onUninstallApp.selector);
17
+ arr.p(AppManagerFacet.onRenewApp.selector);
18
+ arr.p(AppManagerFacet.onUpdateApp.selector);
19
+ arr.p(AppManagerFacet.enableApp.selector);
20
+ arr.p(AppManagerFacet.disableApp.selector);
21
+ arr.p(AppManagerFacet.isAppInstalled.selector);
22
+ arr.p(AppManagerFacet.getAppId.selector);
23
+ arr.p(AppManagerFacet.getAppExpiration.selector);
24
+ arr.p(AppManagerFacet.getInstalledApps.selector);
25
+ arr.p(AppManagerFacet.isAppEntitled.selector);
26
+
27
+ bytes32[] memory selectors_ = arr.asBytes32Array();
28
+ assembly ("memory-safe") {
29
+ res := selectors_
30
+ }
31
+ }
32
+
33
+ function makeInitData() internal pure returns (bytes memory) {
34
+ return abi.encodeCall(AppManagerFacet.__AppManagerFacet_init, ());
35
+ }
36
+
37
+ function deploy() internal returns (address) {
38
+ return LibDeploy.deployCode("AppManagerFacet.sol", "");
39
+ }
40
+ }
@@ -38,8 +38,11 @@ contract InteractBaseAlpha is AlphaHelper {
38
38
  executeDiamondCutsWithLogging(deployer, space, "Space", deploySpace);
39
39
  executeDiamondCutsWithLogging(deployer, spaceOwner, "SpaceOwner", deploySpaceOwner);
40
40
 
41
+ deploySpaceFactory.diamondInitParams(deployer);
41
42
  address spaceFactoryInit = deploySpaceFactory.spaceFactoryInit();
42
43
  bytes memory initData = deploySpaceFactory.spaceFactoryInitData();
44
+ deploySpaceFactory.clearCuts();
45
+
43
46
  executeDiamondCutsWithLogging(
44
47
  deployer,
45
48
  spaceFactory,
@@ -0,0 +1,68 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+ import {IAppAccount} from "src/spaces/facets/account/IAppAccount.sol";
6
+
7
+ // libraries
8
+ import "./AppManagerMod.sol" as AppManager;
9
+
10
+ // contracts
11
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
12
+ import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
13
+
14
+ contract AppManagerFacet is IAppAccount, ReentrancyGuardTransient, Facet {
15
+ function __AppManagerFacet_init() external onlyInitializing {
16
+ _addInterface(type(IAppAccount).interfaceId);
17
+ }
18
+
19
+ function __AppManagerFacet_init_unchained() internal {}
20
+
21
+ function onInstallApp(bytes32 appId, bytes calldata data) external nonReentrant {
22
+ AppManager.installApp(msg.sender, appId, data);
23
+ }
24
+
25
+ function onUninstallApp(bytes32 appId, bytes calldata data) external nonReentrant {
26
+ AppManager.uninstallApp(msg.sender, appId, data);
27
+ }
28
+
29
+ function onRenewApp(bytes32 appId, bytes calldata data) external nonReentrant {
30
+ AppManager.renewApp(msg.sender, appId, data);
31
+ }
32
+
33
+ function onUpdateApp(bytes32 appId, bytes calldata data) external nonReentrant {
34
+ AppManager.updateApp(msg.sender, appId, data);
35
+ }
36
+
37
+ function enableApp(address app) external nonReentrant {
38
+ AppManager.enableApp(msg.sender, app);
39
+ }
40
+
41
+ function disableApp(address app) external nonReentrant {
42
+ AppManager.disableApp(msg.sender, app);
43
+ }
44
+
45
+ function isAppInstalled(address app) external view returns (bool) {
46
+ return AppManager.isAppInstalled(msg.sender, app);
47
+ }
48
+
49
+ function getAppId(address app) external view returns (bytes32) {
50
+ return AppManager.getAppId(msg.sender, app);
51
+ }
52
+
53
+ function getAppExpiration(address app) external view returns (uint48) {
54
+ return AppManager.getAppExpiration(msg.sender, app);
55
+ }
56
+
57
+ function getInstalledApps() external view returns (address[] memory) {
58
+ return AppManager.getInstalledApps(msg.sender);
59
+ }
60
+
61
+ function isAppEntitled(
62
+ address app,
63
+ address publicKey,
64
+ bytes32 permission
65
+ ) external view returns (bool) {
66
+ return AppManager.isAppEntitled(msg.sender, app, publicKey, permission);
67
+ }
68
+ }