@towns-protocol/contracts 0.0.367 → 0.0.369
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 +3 -3
- package/src/apps/facets/registry/AppRegistryBase.sol +2 -1
- package/src/apps/helpers/ISimpleApp.sol +26 -1
- package/src/apps/helpers/SimpleApp.sol +22 -1
- package/src/apps/helpers/SimpleAppStorage.sol +1 -0
- package/src/apps/modules/subscription/SubscriptionModuleStorage.sol +1 -1
- package/src/spaces/facets/membership/IMembership.sol +2 -0
- package/src/spaces/facets/membership/MembershipBase.sol +23 -22
- package/src/spaces/facets/membership/MembershipFacet.sol +6 -0
- package/src/spaces/facets/membership/MembershipStorage.sol +2 -3
- package/src/spaces/facets/membership/join/MembershipJoin.sol +7 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@towns-protocol/contracts",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.369",
|
|
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.369",
|
|
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": "
|
|
60
|
+
"gitHead": "5a4adeead17c71980426b92b98c23952536e08fa"
|
|
61
61
|
}
|
|
@@ -137,7 +137,8 @@ abstract contract AppRegistryBase is IAppRegistryBase, SchemaBase, AttestationBa
|
|
|
137
137
|
params.name,
|
|
138
138
|
params.permissions,
|
|
139
139
|
params.installPrice,
|
|
140
|
-
duration
|
|
140
|
+
duration,
|
|
141
|
+
params.client
|
|
141
142
|
);
|
|
142
143
|
|
|
143
144
|
version = _registerApp(ITownsApp(app), params.client);
|
|
@@ -14,6 +14,18 @@ interface ISimpleAppBase {
|
|
|
14
14
|
/// @notice Thrown when there is no balance to withdraw
|
|
15
15
|
error NoBalanceToWithdraw();
|
|
16
16
|
|
|
17
|
+
/// @notice Thrown when the currency address is the zero address
|
|
18
|
+
error InvalidAddressInput();
|
|
19
|
+
|
|
20
|
+
/// @notice Thrown when the amount is zero
|
|
21
|
+
error InvalidAmount();
|
|
22
|
+
|
|
23
|
+
/// @notice Thrown when the caller is not allowed
|
|
24
|
+
error InvalidCaller();
|
|
25
|
+
|
|
26
|
+
/// @notice Thrown when the currency is invalid
|
|
27
|
+
error InvalidCurrency();
|
|
28
|
+
|
|
17
29
|
/// @notice Emitted when the app is withdrawn
|
|
18
30
|
/// @param recipient The address that received the withdrawal
|
|
19
31
|
/// @param amount The amount of tokens withdrawn
|
|
@@ -27,6 +39,12 @@ interface ISimpleAppBase {
|
|
|
27
39
|
/// @notice Emitted when permissions are updated
|
|
28
40
|
/// @param permissions The new permissions
|
|
29
41
|
event PermissionsUpdated(bytes32[] permissions);
|
|
42
|
+
|
|
43
|
+
/// @notice Emitted when the currency is sent
|
|
44
|
+
/// @param recipient The address that received the currency
|
|
45
|
+
/// @param currency The currency that was sent
|
|
46
|
+
/// @param amount The amount of currency that was sent
|
|
47
|
+
event SendCurrency(address indexed recipient, address indexed currency, uint256 amount);
|
|
30
48
|
}
|
|
31
49
|
|
|
32
50
|
interface ISimpleApp is ISimpleAppBase {
|
|
@@ -34,6 +52,12 @@ interface ISimpleApp is ISimpleAppBase {
|
|
|
34
52
|
/// @param recipient The address to withdraw the ETH to
|
|
35
53
|
function withdrawETH(address recipient) external;
|
|
36
54
|
|
|
55
|
+
/// @notice Sends the currency balance of the app to the recipient
|
|
56
|
+
/// @param recipient The address to send the currency to
|
|
57
|
+
/// @param currency The currency to send
|
|
58
|
+
/// @param amount The amount of currency to send
|
|
59
|
+
function sendCurrency(address recipient, address currency, uint256 amount) external;
|
|
60
|
+
|
|
37
61
|
/// @notice Updates the pricing of the app
|
|
38
62
|
/// @param installPrice The new install price
|
|
39
63
|
/// @param accessDuration The new access duration
|
|
@@ -54,6 +78,7 @@ interface ISimpleApp is ISimpleAppBase {
|
|
|
54
78
|
string calldata appId,
|
|
55
79
|
bytes32[] calldata permissions,
|
|
56
80
|
uint256 installPrice,
|
|
57
|
-
uint48 accessDuration
|
|
81
|
+
uint48 accessDuration,
|
|
82
|
+
address client
|
|
58
83
|
) external;
|
|
59
84
|
}
|
|
@@ -28,7 +28,8 @@ contract SimpleApp is ISimpleApp, Ownable, BaseApp, Initializable {
|
|
|
28
28
|
string calldata appId,
|
|
29
29
|
bytes32[] calldata permissions,
|
|
30
30
|
uint256 installPrice,
|
|
31
|
-
uint48 accessDuration
|
|
31
|
+
uint48 accessDuration,
|
|
32
|
+
address client
|
|
32
33
|
) external initializer {
|
|
33
34
|
_setOwner(owner);
|
|
34
35
|
SimpleAppStorage.Layout storage $ = SimpleAppStorage.getLayout();
|
|
@@ -36,6 +37,7 @@ contract SimpleApp is ISimpleApp, Ownable, BaseApp, Initializable {
|
|
|
36
37
|
$.permissions = permissions;
|
|
37
38
|
$.installPrice = installPrice;
|
|
38
39
|
$.accessDuration = accessDuration;
|
|
40
|
+
$.client = client;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/// @inheritdoc ISimpleApp
|
|
@@ -50,6 +52,19 @@ contract SimpleApp is ISimpleApp, Ownable, BaseApp, Initializable {
|
|
|
50
52
|
emit Withdrawal(recipient, balance);
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
function sendCurrency(address recipient, address currency, uint256 amount) external {
|
|
56
|
+
_checkAllowed();
|
|
57
|
+
|
|
58
|
+
if (recipient == address(0)) ZeroAddress.selector.revertWith();
|
|
59
|
+
if (currency == address(0)) currency = CurrencyTransfer.NATIVE_TOKEN;
|
|
60
|
+
else if (currency.code.length == 0) InvalidCurrency.selector.revertWith();
|
|
61
|
+
if (amount == 0) InvalidAmount.selector.revertWith();
|
|
62
|
+
|
|
63
|
+
CurrencyTransfer.transferCurrency(currency, address(this), recipient, amount);
|
|
64
|
+
|
|
65
|
+
emit SendCurrency(recipient, currency, amount);
|
|
66
|
+
}
|
|
67
|
+
|
|
53
68
|
/// @inheritdoc ISimpleApp
|
|
54
69
|
function updatePricing(uint256 installPrice, uint48 accessDuration) external onlyOwner {
|
|
55
70
|
SimpleAppStorage.Layout storage $ = SimpleAppStorage.getLayout();
|
|
@@ -99,4 +114,10 @@ contract SimpleApp is ISimpleApp, Ownable, BaseApp, Initializable {
|
|
|
99
114
|
function _moduleOwner() internal view override returns (address) {
|
|
100
115
|
return owner();
|
|
101
116
|
}
|
|
117
|
+
|
|
118
|
+
function _checkAllowed() internal view {
|
|
119
|
+
if (msg.sender == owner()) return;
|
|
120
|
+
if (msg.sender == SimpleAppStorage.getLayout().client) return;
|
|
121
|
+
InvalidCaller.selector.revertWith();
|
|
122
|
+
}
|
|
102
123
|
}
|
|
@@ -46,7 +46,7 @@ library SubscriptionModuleStorage {
|
|
|
46
46
|
|
|
47
47
|
function getOperatorBuffer(address operator) internal view returns (uint256) {
|
|
48
48
|
OperatorConfig storage config = getLayout().operatorConfig[operator];
|
|
49
|
-
if (config.interval == 0) return MIN_RENEWAL_BUFFER;
|
|
49
|
+
if (config.interval == 0 || config.buffer == 0) return MIN_RENEWAL_BUFFER;
|
|
50
50
|
return config.buffer;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -72,6 +72,8 @@ interface IMembershipBase {
|
|
|
72
72
|
error Membership__InvalidTransactionType();
|
|
73
73
|
error Membership__Banned();
|
|
74
74
|
error Membership__InvalidAction();
|
|
75
|
+
error Membership__CannotSetFreeAllocationOnPaidSpace();
|
|
76
|
+
error Membership__CannotSetPriceOnFreeSpace();
|
|
75
77
|
|
|
76
78
|
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
|
77
79
|
/* EVENTS */
|
|
@@ -20,28 +20,30 @@ abstract contract MembershipBase is IMembershipBase {
|
|
|
20
20
|
using SafeTransferLib for address;
|
|
21
21
|
|
|
22
22
|
function __MembershipBase_init(Membership memory info, address spaceFactory) internal {
|
|
23
|
-
MembershipStorage.Layout storage
|
|
23
|
+
MembershipStorage.Layout storage $ = MembershipStorage.layout();
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
$.spaceFactory = spaceFactory;
|
|
26
|
+
$.pricingModule = info.pricingModule;
|
|
27
|
+
$.membershipCurrency = CurrencyTransfer.NATIVE_TOKEN;
|
|
28
|
+
$.membershipMaxSupply = info.maxSupply;
|
|
29
29
|
|
|
30
30
|
if (info.freeAllocation > 0) {
|
|
31
31
|
_verifyFreeAllocation(info.freeAllocation);
|
|
32
|
-
|
|
32
|
+
$.freeAllocation = info.freeAllocation;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
$.freeAllocationEnabled = true;
|
|
36
36
|
|
|
37
37
|
if (info.price > 0) {
|
|
38
38
|
_verifyPrice(info.price);
|
|
39
|
+
if (info.freeAllocation > 0)
|
|
40
|
+
Membership__CannotSetFreeAllocationOnPaidSpace.selector.revertWith();
|
|
39
41
|
IMembershipPricing(info.pricingModule).setPrice(info.price);
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
if (info.duration > 0) {
|
|
43
45
|
_verifyDuration(info.duration);
|
|
44
|
-
|
|
46
|
+
$.membershipDuration = info.duration;
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -75,13 +77,13 @@ abstract contract MembershipBase is IMembershipBase {
|
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
function _transferIn(address from, uint256 amount) internal returns (uint256) {
|
|
78
|
-
MembershipStorage.Layout storage
|
|
80
|
+
MembershipStorage.Layout storage $ = MembershipStorage.layout();
|
|
79
81
|
|
|
80
82
|
// get the currency being used for membership
|
|
81
83
|
address currency = _getMembershipCurrency();
|
|
82
84
|
|
|
83
85
|
if (currency == CurrencyTransfer.NATIVE_TOKEN) {
|
|
84
|
-
|
|
86
|
+
$.tokenBalance += amount;
|
|
85
87
|
return amount;
|
|
86
88
|
}
|
|
87
89
|
|
|
@@ -94,7 +96,7 @@ abstract contract MembershipBase is IMembershipBase {
|
|
|
94
96
|
uint256 finalAmount = balanceAfter - balanceBefore;
|
|
95
97
|
if (finalAmount != amount) Membership__InsufficientPayment.selector.revertWith();
|
|
96
98
|
|
|
97
|
-
|
|
99
|
+
$.tokenBalance += finalAmount;
|
|
98
100
|
return finalAmount;
|
|
99
101
|
}
|
|
100
102
|
|
|
@@ -162,15 +164,15 @@ abstract contract MembershipBase is IMembershipBase {
|
|
|
162
164
|
function _getMembershipPrice(
|
|
163
165
|
uint256 totalSupply
|
|
164
166
|
) internal view virtual returns (uint256 membershipPrice) {
|
|
165
|
-
// get free allocation
|
|
166
|
-
uint256 freeAllocation = _getMembershipFreeAllocation();
|
|
167
167
|
address pricingModule = _getPricingModule();
|
|
168
|
-
|
|
169
168
|
IPlatformRequirements platform = _getPlatformRequirements();
|
|
170
|
-
|
|
171
169
|
if (pricingModule == address(0)) return platform.getMembershipFee();
|
|
172
170
|
|
|
171
|
+
// get free allocation
|
|
172
|
+
uint256 freeAllocation = _getMembershipFreeAllocation();
|
|
173
173
|
membershipPrice = IMembershipPricing(pricingModule).getPrice(freeAllocation, totalSupply);
|
|
174
|
+
if (membershipPrice == 0) return 0;
|
|
175
|
+
|
|
174
176
|
uint256 minPrice = platform.getMembershipMinPrice();
|
|
175
177
|
if (membershipPrice < minPrice) return platform.getMembershipFee();
|
|
176
178
|
}
|
|
@@ -183,11 +185,11 @@ abstract contract MembershipBase is IMembershipBase {
|
|
|
183
185
|
uint256 tokenId,
|
|
184
186
|
uint256 totalSupply
|
|
185
187
|
) internal view returns (uint256) {
|
|
186
|
-
MembershipStorage.Layout storage
|
|
188
|
+
MembershipStorage.Layout storage $ = MembershipStorage.layout();
|
|
187
189
|
IPlatformRequirements platform = _getPlatformRequirements();
|
|
188
190
|
|
|
189
191
|
uint256 minFee = platform.getMembershipFee();
|
|
190
|
-
uint256 renewalPrice =
|
|
192
|
+
uint256 renewalPrice = $.renewalPriceByTokenId[tokenId];
|
|
191
193
|
|
|
192
194
|
if (renewalPrice != 0) return FixedPointMathLib.max(renewalPrice, minFee);
|
|
193
195
|
|
|
@@ -207,16 +209,15 @@ abstract contract MembershipBase is IMembershipBase {
|
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
function _setMembershipFreeAllocation(uint256 newAllocation) internal {
|
|
210
|
-
MembershipStorage.Layout storage
|
|
211
|
-
|
|
212
|
-
ds.freeAllocationEnabled = true;
|
|
212
|
+
MembershipStorage.Layout storage $ = MembershipStorage.layout();
|
|
213
|
+
($.freeAllocation, $.freeAllocationEnabled) = (newAllocation, true);
|
|
213
214
|
emit MembershipFreeAllocationUpdated(newAllocation);
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
function _getMembershipFreeAllocation() internal view returns (uint256) {
|
|
217
|
-
MembershipStorage.Layout storage
|
|
218
|
+
MembershipStorage.Layout storage $ = MembershipStorage.layout();
|
|
218
219
|
|
|
219
|
-
if (
|
|
220
|
+
if ($.freeAllocationEnabled) return $.freeAllocation;
|
|
220
221
|
|
|
221
222
|
return _getPlatformRequirements().getMembershipMintLimit();
|
|
222
223
|
}
|
|
@@ -99,6 +99,8 @@ contract MembershipFacet is IMembership, MembershipJoin, ReentrancyGuard, Facet
|
|
|
99
99
|
/// @inheritdoc IMembership
|
|
100
100
|
function setMembershipPrice(uint256 newPrice) external onlyOwner {
|
|
101
101
|
_verifyPrice(newPrice);
|
|
102
|
+
if (newPrice > 0 && _getMembershipFreeAllocation() > 0)
|
|
103
|
+
Membership__CannotSetPriceOnFreeSpace.selector.revertWith();
|
|
102
104
|
IMembershipPricing(_getPricingModule()).setPrice(newPrice);
|
|
103
105
|
}
|
|
104
106
|
|
|
@@ -131,6 +133,10 @@ contract MembershipFacet is IMembership, MembershipJoin, ReentrancyGuard, Facet
|
|
|
131
133
|
Membership__InvalidFreeAllocation.selector.revertWith();
|
|
132
134
|
}
|
|
133
135
|
|
|
136
|
+
if (_getMembershipPrice(_totalSupply()) > 0) {
|
|
137
|
+
Membership__CannotSetFreeAllocationOnPaidSpace.selector.revertWith();
|
|
138
|
+
}
|
|
139
|
+
|
|
134
140
|
// verify newLimit is not more than the allowed platform limit
|
|
135
141
|
_verifyFreeAllocation(newAllocation);
|
|
136
142
|
_setMembershipFreeAllocation(newAllocation);
|
|
@@ -31,10 +31,9 @@ library MembershipStorage {
|
|
|
31
31
|
bool freeAllocationEnabled;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function layout() internal pure returns (Layout storage
|
|
35
|
-
bytes32 slot = STORAGE_SLOT;
|
|
34
|
+
function layout() internal pure returns (Layout storage $) {
|
|
36
35
|
assembly {
|
|
37
|
-
|
|
36
|
+
$.slot := STORAGE_SLOT
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
}
|
|
@@ -74,7 +74,8 @@ abstract contract MembershipJoin is
|
|
|
74
74
|
uint256 totalSupply = _totalSupply();
|
|
75
75
|
uint256 membershipPrice = _getMembershipPrice(totalSupply);
|
|
76
76
|
uint256 freeAllocation = _getMembershipFreeAllocation();
|
|
77
|
-
|
|
77
|
+
|
|
78
|
+
if (membershipPrice == 0) return joinDetails;
|
|
78
79
|
|
|
79
80
|
joinDetails.basePrice = membershipPrice;
|
|
80
81
|
if (freeAllocation > totalSupply) {
|
|
@@ -82,14 +83,14 @@ abstract contract MembershipJoin is
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
// Check if this is a free join due to prepaid supply
|
|
86
|
+
uint256 prepaidSupply = _getPrepaidSupply();
|
|
85
87
|
if (prepaidSupply > 0) {
|
|
86
88
|
joinDetails.isPrepaid = true;
|
|
87
89
|
return joinDetails;
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
// Regular paid join
|
|
91
|
-
joinDetails.amountDue = membershipPrice;
|
|
92
|
-
joinDetails.shouldCharge = true;
|
|
93
|
+
(joinDetails.amountDue, joinDetails.shouldCharge) = (membershipPrice, true);
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
/// @notice Handles the process of joining a space
|
|
@@ -144,9 +145,7 @@ abstract contract MembershipJoin is
|
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
// Consume prepaid membership if applicable
|
|
147
|
-
if (joinDetails.isPrepaid)
|
|
148
|
-
_reducePrepay(1);
|
|
149
|
-
}
|
|
148
|
+
if (joinDetails.isPrepaid) _reducePrepay(1);
|
|
150
149
|
|
|
151
150
|
_validateUserReferral(receiver, referral);
|
|
152
151
|
|
|
@@ -186,10 +185,8 @@ abstract contract MembershipJoin is
|
|
|
186
185
|
}
|
|
187
186
|
|
|
188
187
|
function _validateUserReferral(address receiver, ReferralTypes memory referral) internal view {
|
|
189
|
-
if (referral.userReferral
|
|
190
|
-
|
|
191
|
-
Membership__InvalidAddress.selector.revertWith();
|
|
192
|
-
}
|
|
188
|
+
if (referral.userReferral == receiver || referral.userReferral == msg.sender) {
|
|
189
|
+
Membership__InvalidAddress.selector.revertWith();
|
|
193
190
|
}
|
|
194
191
|
}
|
|
195
192
|
|