@towns-protocol/contracts 0.0.366 → 0.0.368

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.366",
3
+ "version": "0.0.368",
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.366",
38
+ "@towns-protocol/prettier-config": "^0.0.368",
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": "ed5b2f3718b5da967d60c30fc589bdf20568f992"
60
+ "gitHead": "bb014c92cd91d742be6ea53ac56027ec90e4d345"
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
  }
@@ -17,6 +17,7 @@ library SimpleAppStorage {
17
17
  bytes32[] permissions;
18
18
  uint256 installPrice;
19
19
  uint48 accessDuration;
20
+ address client;
20
21
  }
21
22
 
22
23
  function getLayout() internal pure returns (Layout storage l) {
@@ -20,19 +20,19 @@ 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 ds = MembershipStorage.layout();
23
+ MembershipStorage.Layout storage $ = MembershipStorage.layout();
24
24
 
25
- ds.spaceFactory = spaceFactory;
26
- ds.pricingModule = info.pricingModule;
27
- ds.membershipCurrency = CurrencyTransfer.NATIVE_TOKEN;
28
- ds.membershipMaxSupply = info.maxSupply;
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
- ds.freeAllocation = info.freeAllocation;
32
+ $.freeAllocation = info.freeAllocation;
33
33
  }
34
34
 
35
- ds.freeAllocationEnabled = true;
35
+ $.freeAllocationEnabled = true;
36
36
 
37
37
  if (info.price > 0) {
38
38
  _verifyPrice(info.price);
@@ -41,7 +41,7 @@ abstract contract MembershipBase is IMembershipBase {
41
41
 
42
42
  if (info.duration > 0) {
43
43
  _verifyDuration(info.duration);
44
- ds.membershipDuration = info.duration;
44
+ $.membershipDuration = info.duration;
45
45
  }
46
46
  }
47
47
 
@@ -75,13 +75,13 @@ abstract contract MembershipBase is IMembershipBase {
75
75
  }
76
76
 
77
77
  function _transferIn(address from, uint256 amount) internal returns (uint256) {
78
- MembershipStorage.Layout storage ds = MembershipStorage.layout();
78
+ MembershipStorage.Layout storage $ = MembershipStorage.layout();
79
79
 
80
80
  // get the currency being used for membership
81
81
  address currency = _getMembershipCurrency();
82
82
 
83
83
  if (currency == CurrencyTransfer.NATIVE_TOKEN) {
84
- ds.tokenBalance += amount;
84
+ $.tokenBalance += amount;
85
85
  return amount;
86
86
  }
87
87
 
@@ -94,7 +94,7 @@ abstract contract MembershipBase is IMembershipBase {
94
94
  uint256 finalAmount = balanceAfter - balanceBefore;
95
95
  if (finalAmount != amount) Membership__InsufficientPayment.selector.revertWith();
96
96
 
97
- ds.tokenBalance += finalAmount;
97
+ $.tokenBalance += finalAmount;
98
98
  return finalAmount;
99
99
  }
100
100
 
@@ -162,14 +162,12 @@ abstract contract MembershipBase is IMembershipBase {
162
162
  function _getMembershipPrice(
163
163
  uint256 totalSupply
164
164
  ) internal view virtual returns (uint256 membershipPrice) {
165
- // get free allocation
166
- uint256 freeAllocation = _getMembershipFreeAllocation();
167
165
  address pricingModule = _getPricingModule();
168
-
169
166
  IPlatformRequirements platform = _getPlatformRequirements();
170
-
171
167
  if (pricingModule == address(0)) return platform.getMembershipFee();
172
168
 
169
+ // get free allocation
170
+ uint256 freeAllocation = _getMembershipFreeAllocation();
173
171
  membershipPrice = IMembershipPricing(pricingModule).getPrice(freeAllocation, totalSupply);
174
172
  uint256 minPrice = platform.getMembershipMinPrice();
175
173
  if (membershipPrice < minPrice) return platform.getMembershipFee();
@@ -183,11 +181,11 @@ abstract contract MembershipBase is IMembershipBase {
183
181
  uint256 tokenId,
184
182
  uint256 totalSupply
185
183
  ) internal view returns (uint256) {
186
- MembershipStorage.Layout storage ds = MembershipStorage.layout();
184
+ MembershipStorage.Layout storage $ = MembershipStorage.layout();
187
185
  IPlatformRequirements platform = _getPlatformRequirements();
188
186
 
189
187
  uint256 minFee = platform.getMembershipFee();
190
- uint256 renewalPrice = ds.renewalPriceByTokenId[tokenId];
188
+ uint256 renewalPrice = $.renewalPriceByTokenId[tokenId];
191
189
 
192
190
  if (renewalPrice != 0) return FixedPointMathLib.max(renewalPrice, minFee);
193
191
 
@@ -207,16 +205,15 @@ abstract contract MembershipBase is IMembershipBase {
207
205
  }
208
206
 
209
207
  function _setMembershipFreeAllocation(uint256 newAllocation) internal {
210
- MembershipStorage.Layout storage ds = MembershipStorage.layout();
211
- ds.freeAllocation = newAllocation;
212
- ds.freeAllocationEnabled = true;
208
+ MembershipStorage.Layout storage $ = MembershipStorage.layout();
209
+ ($.freeAllocation, $.freeAllocationEnabled) = (newAllocation, true);
213
210
  emit MembershipFreeAllocationUpdated(newAllocation);
214
211
  }
215
212
 
216
213
  function _getMembershipFreeAllocation() internal view returns (uint256) {
217
- MembershipStorage.Layout storage ds = MembershipStorage.layout();
214
+ MembershipStorage.Layout storage $ = MembershipStorage.layout();
218
215
 
219
- if (ds.freeAllocationEnabled) return ds.freeAllocation;
216
+ if ($.freeAllocationEnabled) return $.freeAllocation;
220
217
 
221
218
  return _getPlatformRequirements().getMembershipMintLimit();
222
219
  }
@@ -31,10 +31,9 @@ library MembershipStorage {
31
31
  bool freeAllocationEnabled;
32
32
  }
33
33
 
34
- function layout() internal pure returns (Layout storage l) {
35
- bytes32 slot = STORAGE_SLOT;
34
+ function layout() internal pure returns (Layout storage $) {
36
35
  assembly {
37
- l.slot := slot
36
+ $.slot := STORAGE_SLOT
38
37
  }
39
38
  }
40
39
  }
@@ -74,7 +74,6 @@ abstract contract MembershipJoin is
74
74
  uint256 totalSupply = _totalSupply();
75
75
  uint256 membershipPrice = _getMembershipPrice(totalSupply);
76
76
  uint256 freeAllocation = _getMembershipFreeAllocation();
77
- uint256 prepaidSupply = _getPrepaidSupply();
78
77
 
79
78
  joinDetails.basePrice = membershipPrice;
80
79
  if (freeAllocation > totalSupply) {
@@ -82,14 +81,14 @@ abstract contract MembershipJoin is
82
81
  }
83
82
 
84
83
  // Check if this is a free join due to prepaid supply
84
+ uint256 prepaidSupply = _getPrepaidSupply();
85
85
  if (prepaidSupply > 0) {
86
86
  joinDetails.isPrepaid = true;
87
87
  return joinDetails;
88
88
  }
89
89
 
90
90
  // Regular paid join
91
- joinDetails.amountDue = membershipPrice;
92
- joinDetails.shouldCharge = true;
91
+ (joinDetails.amountDue, joinDetails.shouldCharge) = (membershipPrice, true);
93
92
  }
94
93
 
95
94
  /// @notice Handles the process of joining a space
@@ -144,9 +143,7 @@ abstract contract MembershipJoin is
144
143
  }
145
144
 
146
145
  // Consume prepaid membership if applicable
147
- if (joinDetails.isPrepaid) {
148
- _reducePrepay(1);
149
- }
146
+ if (joinDetails.isPrepaid) _reducePrepay(1);
150
147
 
151
148
  _validateUserReferral(receiver, referral);
152
149
 
@@ -186,10 +183,8 @@ abstract contract MembershipJoin is
186
183
  }
187
184
 
188
185
  function _validateUserReferral(address receiver, ReferralTypes memory referral) internal view {
189
- if (referral.userReferral != address(0)) {
190
- if (referral.userReferral == receiver || referral.userReferral == msg.sender) {
191
- Membership__InvalidAddress.selector.revertWith();
192
- }
186
+ if (referral.userReferral == receiver || referral.userReferral == msg.sender) {
187
+ Membership__InvalidAddress.selector.revertWith();
193
188
  }
194
189
  }
195
190