@towns-protocol/contracts 0.0.354 → 0.0.355
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.355",
|
|
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.355",
|
|
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": "f0192ebd59ae6a99003a0753d1821713e2407bc5"
|
|
61
61
|
}
|
|
@@ -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
|