@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.
- package/package.json +3 -3
- package/scripts/deployments/diamonds/DeployAccountModules.s.sol +188 -0
- package/scripts/deployments/diamonds/DeploySpace.s.sol +0 -7
- package/scripts/deployments/facets/DeployAccountHubFacet.s.sol +47 -0
- package/scripts/deployments/facets/DeployAccountTippingFacet.s.sol +37 -0
- package/scripts/deployments/facets/DeployAppManagerFacet.s.sol +40 -0
- package/scripts/interactions/InteractBaseAlpha.s.sol +3 -0
- package/src/account/facets/app/AppManagerFacet.sol +68 -0
- package/src/account/facets/app/AppManagerMod.sol +321 -0
- package/src/account/facets/hub/AccountHubFacet.sol +226 -0
- package/src/account/facets/hub/AccountHubMod.sol +136 -0
- package/src/account/facets/hub/IAccountHub.sol +25 -0
- package/src/account/facets/tipping/AccountTippingFacet.sol +72 -0
- package/src/account/facets/tipping/AccountTippingMod.sol +144 -0
- package/src/apps/facets/registry/AppRegistryBase.sol +4 -2
- package/src/apps/facets/registry/IAppRegistry.sol +1 -1
- package/src/factory/facets/architect/IArchitect.sol +1 -0
- package/src/factory/facets/create/CreateSpaceBase.sol +2 -9
- package/src/spaces/facets/account/AppAccountStorage.sol +0 -1
- package/src/spaces/facets/membership/IMembership.sol +0 -16
- package/src/spaces/facets/membership/join/MembershipJoin.sol +6 -15
- package/src/spaces/facets/tipping/ITipping.sol +14 -19
- package/src/spaces/facets/tipping/TippingBase.sol +0 -1
- package/src/spaces/facets/xchain/SpaceEntitlementGated.sol +0 -2
- package/scripts/deployments/facets/DeployPrepayFacet.s.sol +0 -31
- package/scripts/interactions/InteractPrepay.s.sol +0 -30
- package/src/spaces/facets/prepay/IPrepay.sol +0 -44
- package/src/spaces/facets/prepay/PrepayBase.sol +0 -27
- package/src/spaces/facets/prepay/PrepayFacet.sol +0 -65
- 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 (
|
|
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
|
-
|
|
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
|
-
/// -
|
|
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
|
-
}
|