@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
@@ -0,0 +1,25 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ interface IAccountHub {
5
+ /// @notice Sets the space factory
6
+ /// @param spaceFactory The address of the space factory
7
+ function setSpaceFactory(address spaceFactory) external;
8
+
9
+ /// @notice Sets the app registry
10
+ /// @param appRegistry The address of the app registry
11
+ function setAppRegistry(address appRegistry) external;
12
+
13
+ /// @notice Gets the space factory
14
+ /// @return The address of the space factory
15
+ function getSpaceFactory() external view returns (address);
16
+
17
+ /// @notice Gets the app registry
18
+ /// @return The address of the app registry
19
+ function getAppRegistry() external view returns (address);
20
+
21
+ /// @notice Checks if an account is installed
22
+ /// @param account The address of the account
23
+ /// @return True if the account is installed, false otherwise
24
+ function isInstalled(address account) external view returns (bool);
25
+ }
@@ -0,0 +1,72 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+ import {ITipping} from "src/spaces/facets/tipping/ITipping.sol";
6
+
7
+ // libraries
8
+ import "./AccountTippingMod.sol" as AccountTipping;
9
+ import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
10
+ import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
11
+
12
+ // contracts
13
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
14
+ import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
15
+
16
+ contract AccountTippingFacet is ITipping, ReentrancyGuardTransient, Facet {
17
+ using EnumerableSetLib for EnumerableSetLib.AddressSet;
18
+ using CustomRevert for bytes4;
19
+
20
+ function __AccountTippingFacet_init() external onlyInitializing {
21
+ _addInterface(type(ITipping).interfaceId);
22
+ }
23
+
24
+ /// @inheritdoc ITipping
25
+ function sendTip(
26
+ TipRecipientType recipientType,
27
+ bytes calldata data
28
+ ) external payable nonReentrant {
29
+ AccountTipping.tipAny(address(this), uint8(recipientType), data);
30
+ }
31
+
32
+ /// @inheritdoc ITipping
33
+ function tip(TipRequest calldata) external payable {
34
+ CustomRevert.revertWith(Deprecated.selector);
35
+ }
36
+
37
+ /// @inheritdoc ITipping
38
+ function tipsByWalletAndCurrency(
39
+ address wallet,
40
+ address currency
41
+ ) external view returns (uint256) {
42
+ return AccountTipping.getStorage().accountStatsByCurrency[wallet][currency].amount;
43
+ }
44
+
45
+ /// @inheritdoc ITipping
46
+ function tipCountByWalletAndCurrency(
47
+ address wallet,
48
+ address currency
49
+ ) external view returns (uint256) {
50
+ return AccountTipping.getStorage().accountStatsByCurrency[wallet][currency].total;
51
+ }
52
+
53
+ /// @inheritdoc ITipping
54
+ function tipsByCurrencyAndTokenId(uint256, address) external pure returns (uint256) {
55
+ CustomRevert.revertWith(Deprecated.selector);
56
+ }
57
+
58
+ /// @inheritdoc ITipping
59
+ function tippingCurrencies() external view returns (address[] memory) {
60
+ return AccountTipping.getStorage().currencies.values();
61
+ }
62
+
63
+ /// @inheritdoc ITipping
64
+ function totalTipsByCurrency(address currency) external view returns (uint256) {
65
+ return AccountTipping.getStorage().currencyStats[currency].total;
66
+ }
67
+
68
+ /// @inheritdoc ITipping
69
+ function tipAmountByCurrency(address currency) external view returns (uint256) {
70
+ return AccountTipping.getStorage().currencyStats[currency].amount;
71
+ }
72
+ }
@@ -0,0 +1,144 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+ import {ITippingBase} from "../../../spaces/facets/tipping/ITipping.sol";
6
+
7
+ // libraries
8
+ import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
9
+ import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
10
+ import {CurrencyTransfer} from "../../../utils/libraries/CurrencyTransfer.sol";
11
+
12
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
13
+ /* TYPES */
14
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
15
+ using CustomRevert for bytes4;
16
+ using EnumerableSetLib for EnumerableSetLib.AddressSet;
17
+
18
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
19
+ /* STORAGE */
20
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
21
+
22
+ // keccak256(abi.encode(uint256(keccak256("towns.account.tipping.mod.storage")) - 1)) & ~bytes32(uint256(0xff))
23
+ bytes32 constant STORAGE_SLOT = 0x2a95e0ca73c50924d5ddd84672da871cae538509d7dabaedae2f730a19f18300;
24
+
25
+ /// @notice Stats for a currency
26
+ /// @param total The total number of tips
27
+ /// @param amount The total amount of tips
28
+ struct Stats {
29
+ uint256 total;
30
+ uint256 amount;
31
+ }
32
+
33
+ /// @notice Storage layout for the AccountTippingMod
34
+ /// @custom:storage-location erc7201:towns.account.tipping.mod.storage
35
+ struct Layout {
36
+ // Global mappings
37
+ EnumerableSetLib.AddressSet currencies;
38
+ mapping(address currency => Stats stats) currencyStats;
39
+ mapping(address account => Stats stats) accountStats;
40
+ mapping(address account => mapping(address currency => Stats stats)) accountStatsByCurrency;
41
+ }
42
+
43
+ /// @notice Returns the storage layout for the AccountTippingMod
44
+ function getStorage() pure returns (Layout storage $) {
45
+ assembly {
46
+ $.slot := STORAGE_SLOT
47
+ }
48
+ }
49
+
50
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
51
+ /* FUNCTIONS */
52
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
53
+
54
+ /// @notice Sends a tip
55
+ /// @param recipientType The type of recipient
56
+ /// @param data The data for the tip
57
+ /// @return tipAmount The amount of the tip
58
+ /// @return protocolFee The protocol fee
59
+ function tipAny(
60
+ address self,
61
+ uint8 recipientType,
62
+ bytes calldata data
63
+ ) returns (uint256 tipAmount, uint256 protocolFee) {
64
+ if (recipientType != uint8(ITippingBase.TipRecipientType.Any))
65
+ ITippingBase.InvalidRecipientType.selector.revertWith();
66
+
67
+ ITippingBase.AnyTipParams memory request = abi.decode(data, (ITippingBase.AnyTipParams));
68
+
69
+ protocolFee;
70
+ tipAmount = request.amount;
71
+
72
+ validateTip(request.sender, request.receiver, request.currency, request.amount);
73
+ depositTip(self, request.currency, request.amount);
74
+ processTip(getStorage(), self, request.receiver, request.currency, request.amount);
75
+
76
+ emit ITippingBase.TipSent(
77
+ msg.sender,
78
+ request.receiver,
79
+ ITippingBase.TipRecipientType.Any,
80
+ request.currency,
81
+ request.amount,
82
+ request.data
83
+ );
84
+ }
85
+
86
+ /// @notice Processes a tip
87
+ /// @param $ The storage layout
88
+ /// @param self The address of the facet
89
+ /// @param receiver The address of the recipient
90
+ /// @param currency The currency of the tip
91
+ /// @param amount The amount of the tip
92
+ function processTip(
93
+ Layout storage $,
94
+ address self,
95
+ address receiver,
96
+ address currency,
97
+ uint256 amount
98
+ ) {
99
+ // Add currency to set
100
+ $.currencies.add(currency);
101
+
102
+ // Update global currency stats
103
+ Stats storage stats = $.currencyStats[currency];
104
+ stats.amount += amount;
105
+ stats.total += 1;
106
+
107
+ // Update account-specific stats
108
+ Stats storage accountStats = $.accountStats[receiver];
109
+ accountStats.amount += amount;
110
+ accountStats.total += 1;
111
+
112
+ Stats storage accountStatsByCurrency = $.accountStatsByCurrency[receiver][currency];
113
+ accountStatsByCurrency.amount += amount;
114
+ accountStatsByCurrency.total += 1;
115
+
116
+ // Transfer currency
117
+ CurrencyTransfer.transferCurrency(currency, self, receiver, amount);
118
+ }
119
+
120
+ /// @notice Validates a tip
121
+ /// @param sender The address of the sender
122
+ /// @param receiver The address of the recipient
123
+ /// @param currency The currency of the tip
124
+ /// @param amount The amount of the tip
125
+ function validateTip(address sender, address receiver, address currency, uint256 amount) view {
126
+ if (currency == address(0)) ITippingBase.CurrencyIsZero.selector.revertWith();
127
+ if (receiver == address(0)) ITippingBase.InvalidAddressInput.selector.revertWith();
128
+ if (amount == 0) ITippingBase.AmountIsZero.selector.revertWith();
129
+ if (sender != msg.sender) ITippingBase.NotSenderOfTip.selector.revertWith();
130
+ if (sender == receiver) ITippingBase.CannotTipSelf.selector.revertWith();
131
+ }
132
+
133
+ /// @notice Deposits a tip
134
+ /// @param self The address of the facet
135
+ /// @param currency The currency of the tip
136
+ /// @param amount The amount of the tip
137
+ function depositTip(address self, address currency, uint256 amount) {
138
+ if (currency == CurrencyTransfer.NATIVE_TOKEN) {
139
+ if (msg.value != amount) ITippingBase.MsgValueMismatch.selector.revertWith();
140
+ } else {
141
+ if (msg.value != 0) ITippingBase.UnexpectedETH.selector.revertWith();
142
+ CurrencyTransfer.transferCurrency(currency, msg.sender, self, amount);
143
+ }
144
+ }
@@ -9,7 +9,6 @@ import {ITownsApp} from "../../ITownsApp.sol";
9
9
  import {IAppRegistryBase} from "./IAppRegistry.sol";
10
10
  import {ISchemaResolver} from "@ethereum-attestation-service/eas-contracts/resolver/ISchemaResolver.sol";
11
11
  import {IPlatformRequirements} from "../../../factory/facets/platform/requirements/IPlatformRequirements.sol";
12
- import {IERC173} from "@towns-protocol/diamond/src/facets/ownable/IERC173.sol";
13
12
  import {IAppAccount} from "../../../spaces/facets/account/IAppAccount.sol";
14
13
  import {IEntitlementsManager} from "../../../spaces/facets/entitlements/IEntitlementsManager.sol";
15
14
 
@@ -320,7 +319,7 @@ abstract contract AppRegistryBase is IAppRegistryBase, SchemaBase, AttestationBa
320
319
  uint256 installPrice
321
320
  ) internal view returns (uint256 totalRequired, uint256 protocolFee) {
322
321
  protocolFee = _getProtocolFee(installPrice);
323
- if (installPrice == 0) return (protocolFee, protocolFee);
322
+ if (installPrice == 0) return (0, protocolFee);
324
323
  return (installPrice + protocolFee, protocolFee);
325
324
  }
326
325
 
@@ -332,6 +331,9 @@ abstract contract AppRegistryBase is IAppRegistryBase, SchemaBase, AttestationBa
332
331
  function _chargeForInstall(address payer, address recipient, uint256 installPrice) internal {
333
332
  (uint256 totalRequired, uint256 protocolFee) = _getTotalRequiredPayment(installPrice);
334
333
 
334
+ if (totalRequired == 0 && msg.value != 0) UnexpectedETH.selector.revertWith();
335
+ if (totalRequired == 0) return;
336
+
335
337
  if (msg.value < totalRequired) InsufficientPayment.selector.revertWith();
336
338
 
337
339
  // Cache platform requirements to avoid multiple storage reads
@@ -3,7 +3,6 @@ pragma solidity ^0.8.23;
3
3
 
4
4
  // interfaces
5
5
  import {ISchemaResolver} from "@ethereum-attestation-service/eas-contracts/resolver/ISchemaResolver.sol";
6
- import {IAppAccount} from "../../../spaces/facets/account/IAppAccount.sol";
7
6
  import {ITownsApp} from "../../ITownsApp.sol";
8
7
 
9
8
  // libraries
@@ -39,6 +38,7 @@ interface IAppRegistryBase {
39
38
  error NotAllowed();
40
39
  error ClientAlreadyRegistered();
41
40
  error ClientNotRegistered();
41
+ error UnexpectedETH();
42
42
 
43
43
  error AppRegistry__InvalidDuration();
44
44
  error AppRegistry__InvalidPrice();
@@ -97,6 +97,7 @@ interface IArchitectBase {
97
97
  error Architect__InvalidAddress();
98
98
  error Architect__NotContract();
99
99
  error Architect__InvalidPricingModule();
100
+ error Architect__UnexpectedETH();
100
101
 
101
102
  event Architect__ProxyInitializerSet(address indexed proxyInitializer);
102
103
  }
@@ -12,7 +12,6 @@ import {IUserEntitlement} from "../../../spaces/entitlements/user/IUserEntitleme
12
12
  import {IChannel} from "../../../spaces/facets/channels/IChannel.sol";
13
13
  import {IEntitlementsManager} from "../../../spaces/facets/entitlements/IEntitlementsManager.sol";
14
14
  import {IMembershipBase} from "../../../spaces/facets/membership/IMembership.sol";
15
- import {IPrepay} from "../../../spaces/facets/prepay/IPrepay.sol";
16
15
  import {IRoles, IRolesBase} from "../../../spaces/facets/roles/IRoles.sol";
17
16
  import {IArchitectBase} from "../architect/IArchitect.sol";
18
17
 
@@ -43,6 +42,7 @@ abstract contract CreateSpaceBase is IArchitectBase {
43
42
  CreateSpace calldata space,
44
43
  SpaceOptions memory spaceOptions
45
44
  ) internal returns (address spaceAddress) {
45
+ if (msg.value > 0) revert Architect__UnexpectedETH();
46
46
  Validator.checkAddress(space.membership.settings.pricingModule);
47
47
  Validator.checkAddress(spaceOptions.to);
48
48
 
@@ -54,10 +54,6 @@ abstract contract CreateSpaceBase is IArchitectBase {
54
54
  space.channel,
55
55
  spaceOptions
56
56
  );
57
-
58
- if (space.prepay.supply > 0) {
59
- IPrepay(spaceAddress).prepayMembership{value: msg.value}(space.prepay.supply);
60
- }
61
57
  }
62
58
 
63
59
  /// @dev Converts legacy CreateSpaceOld format and creates space
@@ -65,6 +61,7 @@ abstract contract CreateSpaceBase is IArchitectBase {
65
61
  CreateSpaceOld calldata space,
66
62
  SpaceOptions memory spaceOptions
67
63
  ) internal returns (address spaceAddress) {
64
+ if (msg.value > 0) revert Architect__UnexpectedETH();
68
65
  Validator.checkAddress(space.membership.settings.pricingModule);
69
66
  Validator.checkAddress(spaceOptions.to);
70
67
 
@@ -84,10 +81,6 @@ abstract contract CreateSpaceBase is IArchitectBase {
84
81
  space.channel,
85
82
  spaceOptions
86
83
  );
87
-
88
- if (space.prepay.supply > 0) {
89
- IPrepay(spaceAddress).prepayMembership{value: msg.value}(space.prepay.supply);
90
- }
91
84
  }
92
85
 
93
86
  function _createSpaceCore(
@@ -6,7 +6,6 @@ import {IAppRegistry} from "src/apps/facets/registry/IAppRegistry.sol";
6
6
 
7
7
  // libraries
8
8
  import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
9
- import {ExecutorStorage} from "src/spaces/facets/executor/ExecutorStorage.sol";
10
9
  import {DependencyLib} from "src/spaces/facets/DependencyLib.sol";
11
10
  import {EMPTY_UID} from "@ethereum-attestation-service/eas-contracts/Common.sol";
12
11
 
@@ -41,38 +41,22 @@ interface IMembershipBase {
41
41
  string referralCode;
42
42
  }
43
43
 
44
- struct PricingDetails {
45
- uint256 basePrice;
46
- uint256 amountDue;
47
- bool shouldCharge;
48
- bool isPrepaid;
49
- }
50
-
51
44
  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
52
45
  /* ERRORS */
53
46
  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
54
47
 
55
48
  error Membership__InvalidAddress();
56
- error Membership__InvalidPrice();
57
- error Membership__InvalidLimit();
58
- error Membership__InvalidCurrency();
59
- error Membership__InvalidFeeRecipient();
60
49
  error Membership__InvalidDuration();
61
50
  error Membership__InvalidMaxSupply();
62
51
  error Membership__InvalidFreeAllocation();
63
52
  error Membership__InvalidPricingModule();
64
- error Membership__AlreadyMember();
65
53
  error Membership__InsufficientPayment();
66
54
  error Membership__MaxSupplyReached();
67
- error Membership__InvalidTokenId();
68
- error Membership__NotExpired();
69
- error Membership__InsufficientAllowance();
70
55
  error Membership__InvalidPayment();
71
56
  error Membership__InvalidTransactionType();
72
57
  error Membership__Banned();
73
58
  error Membership__InvalidAction();
74
59
  error Membership__CannotSetFreeAllocationOnPaidSpace();
75
- error Membership__CannotSetPriceOnFreeSpace();
76
60
 
77
61
  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
78
62
  /* EVENTS */
@@ -22,7 +22,6 @@ import {DispatcherBase} from "../../dispatcher/DispatcherBase.sol";
22
22
  import {Entitled} from "../../Entitled.sol";
23
23
  import {EntitlementGatedBase} from "../../gated/EntitlementGatedBase.sol";
24
24
  import {PointsBase} from "../../points/PointsBase.sol";
25
- import {PrepayBase} from "../../prepay/PrepayBase.sol";
26
25
  import {ReferralsBase} from "../../referrals/ReferralsBase.sol";
27
26
  import {RolesBase} from "../../roles/RolesBase.sol";
28
27
  import {MembershipBase} from "../MembershipBase.sol";
@@ -41,7 +40,6 @@ abstract contract MembershipJoin is
41
40
  RolesBase,
42
41
  EntitlementGatedBase,
43
42
  Entitled,
44
- PrepayBase,
45
43
  PointsBase,
46
44
  ERC721ABase
47
45
  {
@@ -53,6 +51,12 @@ abstract contract MembershipJoin is
53
51
  /// @notice Constant representing the joinSpace(address) function selector
54
52
  bytes4 internal constant JOIN_SPACE_SELECTOR = bytes4(keccak256("joinSpace(address)"));
55
53
 
54
+ struct PricingDetails {
55
+ uint256 basePrice;
56
+ uint256 amountDue;
57
+ bool shouldCharge;
58
+ }
59
+
56
60
  /// @notice Encodes data for joining a space
57
61
  /// @param selector The type of transaction (join with or without referral)
58
62
  /// @param sender The address of the sender
@@ -82,13 +86,6 @@ abstract contract MembershipJoin is
82
86
  return joinDetails;
83
87
  }
84
88
 
85
- // Check if this is a free join due to prepaid supply
86
- uint256 prepaidSupply = _getPrepaidSupply();
87
- if (prepaidSupply > 0) {
88
- joinDetails.isPrepaid = true;
89
- return joinDetails;
90
- }
91
-
92
89
  (uint256 totalRequired, ) = _getTotalMembershipPayment(membershipPrice);
93
90
  (joinDetails.amountDue, joinDetails.shouldCharge) = (totalRequired, true);
94
91
  }
@@ -105,9 +102,6 @@ abstract contract MembershipJoin is
105
102
  Membership__InsufficientPayment.selector.revertWith();
106
103
  }
107
104
 
108
- // Consume prepaid membership if applicable
109
- if (joinDetails.isPrepaid) _reducePrepay(1);
110
-
111
105
  bytes32 transactionId = _registerTransaction(
112
106
  receiver,
113
107
  _encodeJoinSpaceData(JOIN_SPACE_SELECTOR, msg.sender, receiver, "")
@@ -144,9 +138,6 @@ abstract contract MembershipJoin is
144
138
  Membership__InsufficientPayment.selector.revertWith();
145
139
  }
146
140
 
147
- // Consume prepaid membership if applicable
148
- if (joinDetails.isPrepaid) _reducePrepay(1);
149
-
150
141
  _validateUserReferral(receiver, referral);
151
142
 
152
143
  bytes memory referralData = abi.encode(referral);
@@ -2,26 +2,27 @@
2
2
  pragma solidity ^0.8.23;
3
3
 
4
4
  interface ITippingBase {
5
- // =============================================================
6
- // Enums
7
- // =============================================================
8
-
9
5
  enum TipRecipientType {
10
6
  Member, // Tips to token holders
11
7
  Bot, // Tips to bot wallets
12
- Pool // Tips to pool wallets
8
+ Any // Tips to any address
13
9
  }
14
10
 
15
- // =============================================================
16
- // Structs
17
- // =============================================================
18
-
19
11
  struct TipMetadata {
20
12
  bytes32 messageId;
21
13
  bytes32 channelId;
22
14
  bytes data; // Extensible metadata
23
15
  }
24
16
 
17
+ /// @notice Params for any tip
18
+ struct AnyTipParams {
19
+ address currency;
20
+ address sender;
21
+ address receiver;
22
+ uint256 amount;
23
+ bytes data;
24
+ }
25
+
25
26
  /// @notice Params for Member tips (includes tokenId)
26
27
  struct MembershipTipParams {
27
28
  address receiver;
@@ -50,10 +51,6 @@ interface ITippingBase {
50
51
  bytes32 channelId;
51
52
  }
52
53
 
53
- // =============================================================
54
- // Events
55
- // =============================================================
56
-
57
54
  event TipSent(
58
55
  address indexed sender,
59
56
  address indexed receiver,
@@ -74,10 +71,6 @@ interface ITippingBase {
74
71
  bytes32 channelId
75
72
  );
76
73
 
77
- // =============================================================
78
- // Errors
79
- // =============================================================
80
-
81
74
  error InvalidRecipientType();
82
75
  error InvalidTipData();
83
76
  error TokenDoesNotExist();
@@ -87,6 +80,9 @@ interface ITippingBase {
87
80
  error CurrencyIsZero();
88
81
  error MsgValueMismatch();
89
82
  error UnexpectedETH();
83
+ error NotSenderOfTip();
84
+ error Deprecated();
85
+ error InvalidAddressInput();
90
86
  }
91
87
 
92
88
  interface ITipping is ITippingBase {
@@ -94,9 +90,8 @@ interface ITipping is ITippingBase {
94
90
  /// @param recipientType The type of recipient (Member, Wallet, Bot, Pool)
95
91
  /// @param data ABI-encoded tip params based on recipientType:
96
92
  /// - Member: abi.encode(MembershipTipParams)
97
- /// - Wallet: abi.encode(WalletTipParams)
98
93
  /// - Bot: abi.encode(BotTipParams)
99
- /// - Pool: Reserved for future implementation
94
+ /// - Any: abi.encode(AnyTipParams)
100
95
  function sendTip(TipRecipientType recipientType, bytes calldata data) external payable;
101
96
 
102
97
  /// @notice Sends a tip to a space member (legacy)
@@ -6,7 +6,6 @@ import {ITippingBase} from "./ITipping.sol";
6
6
  import {ITownsPointsBase} from "../../../airdrop/points/ITownsPoints.sol";
7
7
  import {IFeeManager} from "../../../factory/facets/fee/IFeeManager.sol";
8
8
  import {FeeTypesLib} from "../../../factory/facets/fee/FeeTypesLib.sol";
9
- import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
10
9
 
11
10
  // libraries
12
11
  import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
@@ -4,8 +4,6 @@ pragma solidity ^0.8.23;
4
4
  // interfaces
5
5
  import {IMembership} from "../membership/IMembership.sol";
6
6
 
7
- // libraries
8
-
9
7
  // contracts
10
8
  import {EntitlementGated} from "../gated/EntitlementGated.sol";
11
9
  import {MembershipJoin} from "../membership/join/MembershipJoin.sol";
@@ -1,31 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- //interfaces
5
- import {IDiamond} from "@towns-protocol/diamond/src/Diamond.sol";
6
- import {IPrepay} from "src/spaces/facets/prepay/IPrepay.sol";
7
-
8
- //libraries
9
- import {LibDeploy} from "@towns-protocol/diamond/src/utils/LibDeploy.sol";
10
-
11
- //contracts
12
-
13
- library DeployPrepayFacet {
14
- function selectors() internal pure returns (bytes4[] memory res) {
15
- res = new bytes4[](3);
16
- res[0] = IPrepay.prepayMembership.selector;
17
- res[1] = IPrepay.prepaidMembershipSupply.selector;
18
- res[2] = IPrepay.calculateMembershipPrepayFee.selector;
19
- }
20
-
21
- function makeCut(
22
- address facetAddress,
23
- IDiamond.FacetCutAction action
24
- ) internal pure returns (IDiamond.FacetCut memory) {
25
- return IDiamond.FacetCut(facetAddress, action, selectors());
26
- }
27
-
28
- function deploy() internal returns (address) {
29
- return LibDeploy.deployCode("PrepayFacet.sol", "");
30
- }
31
- }
@@ -1,30 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- // interfaces
5
-
6
- // libraries
7
-
8
- // contracts
9
- import {Interaction} from "scripts/common/Interaction.s.sol";
10
- import {IPrepay} from "src/spaces/facets/prepay/IPrepay.sol";
11
-
12
- // debuggging
13
- import {console} from "forge-std/console.sol";
14
-
15
- contract InteractPrepay is Interaction {
16
- IPrepay prepay = IPrepay(0x0000000000000000000000000000000000000000);
17
-
18
- function __interact(address deployer) internal override {
19
- uint256 expectedAmount = 1000;
20
- uint256 totalAmount = prepay.calculateMembershipPrepayFee(expectedAmount);
21
-
22
- console.log("paying:", totalAmount);
23
-
24
- vm.startBroadcast(deployer);
25
- IPrepay(prepay).prepayMembership{value: totalAmount}(expectedAmount);
26
- vm.stopBroadcast();
27
-
28
- console.log("prepaidSupply", prepay.prepaidMembershipSupply());
29
- }
30
- }
@@ -1,44 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- // interfaces
5
-
6
- // libraries
7
-
8
- // contracts
9
- interface IPrepayBase {
10
- // =============================================================
11
- // ERRORS
12
- // =============================================================
13
- error Prepay__InvalidSupplyAmount();
14
- error Prepay__InvalidAmount();
15
- error Prepay__InvalidAddress();
16
- error Prepay__InvalidMembership();
17
- error Prepay__NotAllowed();
18
-
19
- // =============================================================
20
- // EVENTS
21
- // =============================================================
22
- event Prepay__Prepaid(uint256 supply);
23
- }
24
-
25
- interface IPrepay is IPrepayBase {
26
- /**
27
- * @notice Prepay a membership
28
- * @param supply The amount of memberships to prepay
29
- */
30
- function prepayMembership(uint256 supply) external payable;
31
-
32
- /**
33
- * @notice Get the prepaid supply
34
- * @return The remaining prepaid supply
35
- */
36
- function prepaidMembershipSupply() external view returns (uint256);
37
-
38
- /**
39
- * @notice Calculate the prepay fee for a given supply
40
- * @param supply The supply to calculate the fee for
41
- * @return The fee
42
- */
43
- function calculateMembershipPrepayFee(uint256 supply) external view returns (uint256);
44
- }