@towns-protocol/contracts 0.0.354 → 0.0.356
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.
|
|
3
|
+
"version": "0.0.356",
|
|
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.
|
|
38
|
+
"@towns-protocol/prettier-config": "^0.0.356",
|
|
39
39
|
"@typechain/ethers-v5": "^10.1.1",
|
|
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": "
|
|
60
|
+
"gitHead": "c3283b1d3e158931ffaca0c745e36e76795965e1"
|
|
61
61
|
}
|
|
@@ -15,7 +15,7 @@ library DeploySubscriptionModuleFacet {
|
|
|
15
15
|
using DynamicArrayLib for DynamicArrayLib.DynamicArray;
|
|
16
16
|
|
|
17
17
|
function selectors() internal pure returns (bytes4[] memory res) {
|
|
18
|
-
DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(
|
|
18
|
+
DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(20);
|
|
19
19
|
arr.p(SubscriptionModuleFacet.moduleId.selector);
|
|
20
20
|
arr.p(SubscriptionModuleFacet.onInstall.selector);
|
|
21
21
|
arr.p(SubscriptionModuleFacet.onUninstall.selector);
|
|
@@ -28,6 +28,7 @@ library DeploySubscriptionModuleFacet {
|
|
|
28
28
|
arr.p(SubscriptionModuleFacet.batchProcessRenewals.selector);
|
|
29
29
|
arr.p(SubscriptionModuleFacet.getRenewalBuffer.selector);
|
|
30
30
|
arr.p(SubscriptionModuleFacet.getSubscription.selector);
|
|
31
|
+
arr.p(SubscriptionModuleFacet.activateSubscription.selector);
|
|
31
32
|
arr.p(SubscriptionModuleFacet.pauseSubscription.selector);
|
|
32
33
|
arr.p(SubscriptionModuleFacet.getEntityIds.selector);
|
|
33
34
|
arr.p(SubscriptionModuleFacet.isOperator.selector);
|
|
@@ -125,6 +125,17 @@ interface IAppRegistry is IAppRegistryBase {
|
|
|
125
125
|
/// @return appId The attestation UID of the registered app
|
|
126
126
|
function registerApp(ITownsApp app, address client) external payable returns (bytes32 appId);
|
|
127
127
|
|
|
128
|
+
/// @notice Upgrade an app
|
|
129
|
+
/// @param app The app address to update
|
|
130
|
+
/// @param client The client address part of the app's identity
|
|
131
|
+
/// @param appId The app ID to upgrade
|
|
132
|
+
/// @return appId The new app ID of the updated app
|
|
133
|
+
function upgradeApp(
|
|
134
|
+
ITownsApp app,
|
|
135
|
+
address client,
|
|
136
|
+
bytes32 appId
|
|
137
|
+
) external payable returns (bytes32);
|
|
138
|
+
|
|
128
139
|
/// @notice Remove a app from the registry
|
|
129
140
|
/// @param appId The app ID to remove
|
|
130
141
|
function removeApp(bytes32 appId) external;
|
|
@@ -147,6 +158,11 @@ interface IAppRegistry is IAppRegistryBase {
|
|
|
147
158
|
/// @param data The data to pass to the app's onUninstall function
|
|
148
159
|
function uninstallApp(ITownsApp app, IAppAccount account, bytes calldata data) external;
|
|
149
160
|
|
|
161
|
+
/// @notice Update an app to the latest version
|
|
162
|
+
/// @param app The app address to update
|
|
163
|
+
/// @param account The account to update the app to
|
|
164
|
+
function updateApp(ITownsApp app, IAppAccount account) external;
|
|
165
|
+
|
|
150
166
|
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
|
151
167
|
/* Admin */
|
|
152
168
|
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
|
@@ -8,6 +8,7 @@ import {IValidationHookModule} from "@erc6900/reference-implementation/interface
|
|
|
8
8
|
import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol";
|
|
9
9
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
10
10
|
import {ISubscriptionModule} from "./ISubscriptionModule.sol";
|
|
11
|
+
import {IMembership} from "../../../spaces/facets/membership/IMembership.sol";
|
|
11
12
|
|
|
12
13
|
// libraries
|
|
13
14
|
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";
|
|
@@ -22,7 +23,6 @@ import {Subscription, SubscriptionModuleStorage} from "./SubscriptionModuleStora
|
|
|
22
23
|
// contracts
|
|
23
24
|
import {ModuleBase} from "modular-account/src/modules/ModuleBase.sol";
|
|
24
25
|
import {OwnableBase} from "@towns-protocol/diamond/src/facets/ownable/OwnableBase.sol";
|
|
25
|
-
import {MembershipFacet} from "../../../spaces/facets/membership/MembershipFacet.sol";
|
|
26
26
|
import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
|
|
27
27
|
|
|
28
28
|
/// @title Subscription Module
|
|
@@ -75,13 +75,19 @@ contract SubscriptionModuleFacet is
|
|
|
75
75
|
|
|
76
76
|
Validator.checkAddress(space);
|
|
77
77
|
|
|
78
|
+
if (entityId == 0) SubscriptionModule__InvalidEntityId.selector.revertWith();
|
|
79
|
+
|
|
78
80
|
if (IERC721(space).ownerOf(tokenId) != msg.sender)
|
|
79
81
|
SubscriptionModule__InvalidTokenOwner.selector.revertWith();
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
IMembership membershipFacet = IMembership(space);
|
|
82
84
|
uint256 expiresAt = membershipFacet.expiresAt(tokenId);
|
|
83
85
|
|
|
84
86
|
SubscriptionModuleStorage.Layout storage $ = SubscriptionModuleStorage.getLayout();
|
|
87
|
+
|
|
88
|
+
if (!$.entityIds[msg.sender].add(entityId))
|
|
89
|
+
SubscriptionModule__InvalidEntityId.selector.revertWith();
|
|
90
|
+
|
|
85
91
|
Subscription storage sub = $.subscriptions[msg.sender][entityId];
|
|
86
92
|
sub.space = space;
|
|
87
93
|
sub.active = true;
|
|
@@ -89,8 +95,6 @@ contract SubscriptionModuleFacet is
|
|
|
89
95
|
sub.installTime = uint40(block.timestamp);
|
|
90
96
|
sub.nextRenewalTime = _calculateNextRenewalTime(expiresAt, sub.installTime);
|
|
91
97
|
|
|
92
|
-
$.entityIds[msg.sender].add(entityId);
|
|
93
|
-
|
|
94
98
|
emit SubscriptionConfigured(msg.sender, entityId, space, tokenId, sub.nextRenewalTime);
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -102,6 +106,7 @@ contract SubscriptionModuleFacet is
|
|
|
102
106
|
|
|
103
107
|
if (!$.entityIds[msg.sender].remove(entityId))
|
|
104
108
|
SubscriptionModule__InvalidEntityId.selector.revertWith();
|
|
109
|
+
|
|
105
110
|
delete $.subscriptions[msg.sender][entityId];
|
|
106
111
|
|
|
107
112
|
emit SubscriptionDeactivated(msg.sender, entityId);
|
|
@@ -184,6 +189,8 @@ contract SubscriptionModuleFacet is
|
|
|
184
189
|
if (!$.operators.contains(msg.sender))
|
|
185
190
|
SubscriptionModule__InvalidCaller.selector.revertWith();
|
|
186
191
|
|
|
192
|
+
IMembership membershipFacet;
|
|
193
|
+
|
|
187
194
|
for (uint256 i; i < paramsLen; ++i) {
|
|
188
195
|
Subscription storage sub = $.subscriptions[params[i].account][params[i].entityId];
|
|
189
196
|
|
|
@@ -213,15 +220,7 @@ contract SubscriptionModuleFacet is
|
|
|
213
220
|
continue;
|
|
214
221
|
}
|
|
215
222
|
|
|
216
|
-
|
|
217
|
-
uint256 expiresAt = membershipFacet.expiresAt(sub.tokenId);
|
|
218
|
-
|
|
219
|
-
// Sync next renewal time from on-chain expiration if user called renewMembership directly
|
|
220
|
-
uint40 correctNextRenewalTime = _calculateNextRenewalTime(expiresAt, sub.installTime);
|
|
221
|
-
if (sub.nextRenewalTime != correctNextRenewalTime) {
|
|
222
|
-
sub.nextRenewalTime = correctNextRenewalTime;
|
|
223
|
-
emit SubscriptionSynced(params[i].account, params[i].entityId, sub.nextRenewalTime);
|
|
224
|
-
}
|
|
223
|
+
membershipFacet = IMembership(sub.space);
|
|
225
224
|
|
|
226
225
|
uint256 actualRenewalPrice = membershipFacet.getMembershipRenewalPrice(sub.tokenId);
|
|
227
226
|
|
|
@@ -235,6 +234,14 @@ contract SubscriptionModuleFacet is
|
|
|
235
234
|
continue;
|
|
236
235
|
}
|
|
237
236
|
|
|
237
|
+
uint256 expiresAt = membershipFacet.expiresAt(sub.tokenId);
|
|
238
|
+
uint40 correctNextRenewalTime = _calculateNextRenewalTime(expiresAt, sub.installTime);
|
|
239
|
+
|
|
240
|
+
if (sub.nextRenewalTime != correctNextRenewalTime) {
|
|
241
|
+
sub.nextRenewalTime = correctNextRenewalTime;
|
|
242
|
+
emit SubscriptionSynced(params[i].account, params[i].entityId, sub.nextRenewalTime);
|
|
243
|
+
}
|
|
244
|
+
|
|
238
245
|
_processRenewal(sub, params[i], membershipFacet, actualRenewalPrice);
|
|
239
246
|
}
|
|
240
247
|
}
|
|
@@ -254,17 +261,29 @@ contract SubscriptionModuleFacet is
|
|
|
254
261
|
|
|
255
262
|
/// @inheritdoc ISubscriptionModule
|
|
256
263
|
function activateSubscription(uint32 entityId) external nonReentrant {
|
|
257
|
-
|
|
258
|
-
entityId
|
|
259
|
-
];
|
|
264
|
+
SubscriptionModuleStorage.Layout storage $ = SubscriptionModuleStorage.getLayout();
|
|
260
265
|
|
|
261
|
-
if (
|
|
266
|
+
if (!_hasEntityId($, msg.sender, entityId))
|
|
267
|
+
SubscriptionModule__InvalidEntityId.selector.revertWith();
|
|
262
268
|
|
|
263
|
-
sub
|
|
269
|
+
Subscription storage sub = $.subscriptions[msg.sender][entityId];
|
|
270
|
+
|
|
271
|
+
if (sub.active) SubscriptionModule__ActiveSubscription.selector.revertWith();
|
|
264
272
|
|
|
265
273
|
address owner = IERC721(sub.space).ownerOf(sub.tokenId);
|
|
266
274
|
if (msg.sender != owner) SubscriptionModule__InvalidCaller.selector.revertWith();
|
|
267
275
|
|
|
276
|
+
IMembership membershipFacet = IMembership(sub.space);
|
|
277
|
+
uint256 expiresAt = membershipFacet.expiresAt(sub.tokenId);
|
|
278
|
+
|
|
279
|
+
// 6. Always sync renewal time to current membership state
|
|
280
|
+
uint40 correctNextRenewalTime = _calculateNextRenewalTime(expiresAt, sub.installTime);
|
|
281
|
+
if (sub.nextRenewalTime != correctNextRenewalTime) {
|
|
282
|
+
sub.nextRenewalTime = correctNextRenewalTime;
|
|
283
|
+
emit SubscriptionSynced(msg.sender, entityId, sub.nextRenewalTime);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
sub.active = true;
|
|
268
287
|
emit SubscriptionActivated(msg.sender, entityId);
|
|
269
288
|
}
|
|
270
289
|
|
|
@@ -276,10 +295,10 @@ contract SubscriptionModuleFacet is
|
|
|
276
295
|
|
|
277
296
|
if (!sub.active) SubscriptionModule__InactiveSubscription.selector.revertWith();
|
|
278
297
|
|
|
279
|
-
_pauseSubscription(sub, msg.sender, entityId);
|
|
280
|
-
|
|
281
298
|
address owner = IERC721(sub.space).ownerOf(sub.tokenId);
|
|
282
299
|
if (msg.sender != owner) SubscriptionModule__InvalidCaller.selector.revertWith();
|
|
300
|
+
|
|
301
|
+
_pauseSubscription(sub, msg.sender, entityId);
|
|
283
302
|
}
|
|
284
303
|
|
|
285
304
|
/// @inheritdoc ISubscriptionModule
|
|
@@ -310,17 +329,25 @@ contract SubscriptionModuleFacet is
|
|
|
310
329
|
/* Internal */
|
|
311
330
|
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
|
312
331
|
|
|
332
|
+
function _hasEntityId(
|
|
333
|
+
SubscriptionModuleStorage.Layout storage $,
|
|
334
|
+
address account,
|
|
335
|
+
uint32 entityId
|
|
336
|
+
) internal view returns (bool) {
|
|
337
|
+
return $.entityIds[account].contains(entityId);
|
|
338
|
+
}
|
|
339
|
+
|
|
313
340
|
/// @dev Processes a single subscription renewal
|
|
314
341
|
/// @param sub The subscription to renew
|
|
315
342
|
/// @param params The parameters for the renewal
|
|
316
343
|
function _processRenewal(
|
|
317
344
|
Subscription storage sub,
|
|
318
345
|
RenewalParams calldata params,
|
|
319
|
-
|
|
346
|
+
IMembership membershipFacet,
|
|
320
347
|
uint256 actualRenewalPrice
|
|
321
348
|
) internal {
|
|
322
349
|
// Construct the renewal call to space contract
|
|
323
|
-
bytes memory renewalCall = abi.encodeCall(
|
|
350
|
+
bytes memory renewalCall = abi.encodeCall(IMembership.renewMembership, (sub.tokenId));
|
|
324
351
|
|
|
325
352
|
// Create the data parameter for executeWithRuntimeValidation
|
|
326
353
|
// This should be an execute() call to the space contract
|