@towns-protocol/contracts 0.0.455 → 1.0.2
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 +4 -4
- package/scripts/deployments/diamonds/DeployL1Resolver.s.sol +155 -0
- package/scripts/deployments/diamonds/DeployL2Registrar.s.sol +171 -0
- package/scripts/deployments/diamonds/DeployL2Resolver.s.sol +196 -0
- package/scripts/deployments/diamonds/DeploySpaceFactory.s.sol +0 -12
- package/scripts/deployments/facets/DeployAddrResolverFacet.s.sol +36 -0
- package/scripts/deployments/facets/DeployArchitect.s.sol +1 -3
- package/scripts/deployments/facets/DeployContentHashResolverFacet.s.sol +34 -0
- package/scripts/deployments/facets/DeployCreateSpace.s.sol +2 -1
- package/scripts/deployments/facets/{DeploySpaceFactoryInit.s.sol → DeployExtendedResolverFacet.s.sol} +10 -10
- package/scripts/deployments/facets/DeployL1ResolverFacet.s.sol +61 -0
- package/scripts/deployments/facets/DeployL2RegistrarFacet.s.sol +56 -0
- package/scripts/deployments/facets/DeployL2RegistryFacet.s.sol +71 -0
- package/scripts/deployments/facets/DeployNodeRegistry.s.sol +4 -1
- package/scripts/deployments/facets/DeployTextResolverFacet.s.sol +34 -0
- package/scripts/deployments/utils/DeployDomainFeeHook.s.sol +78 -0
- package/scripts/interactions/InteractAlphaPost.s.sol +0 -7
- package/scripts/interactions/InteractBaseAlpha.s.sol +1 -14
- package/scripts/interactions/InteractDomainFee.s.sol +62 -0
- package/scripts/interactions/InteractSetStreamDistributionBalancingAdvantage.s.sol +42 -0
- package/scripts/interactions/InteractSetStreamDistributionRequiredOperators.s.sol +32 -0
- package/scripts/interactions/helpers/RiverConfigValues.sol +6 -0
- package/src/domains/facets/l1/IL1ResolverService.sol +20 -0
- package/src/domains/facets/l1/L1ResolverFacet.sol +100 -0
- package/src/domains/facets/l1/L1ResolverMod.sol +245 -0
- package/src/domains/facets/l2/AddrResolverFacet.sol +59 -0
- package/src/domains/facets/l2/ContentHashResolverFacet.sol +41 -0
- package/src/domains/facets/l2/ExtendedResolverFacet.sol +38 -0
- package/src/domains/facets/l2/IL2Registry.sol +79 -0
- package/src/domains/facets/l2/L2RegistryFacet.sol +203 -0
- package/src/domains/facets/l2/TextResolverFacet.sol +43 -0
- package/src/domains/facets/l2/modules/AddrResolverMod.sol +110 -0
- package/src/domains/facets/l2/modules/ContentHashResolverMod.sol +60 -0
- package/src/domains/facets/l2/modules/L2RegistryMod.sol +286 -0
- package/src/domains/facets/l2/modules/TextResolverMod.sol +62 -0
- package/src/domains/facets/l2/modules/VersionRecordMod.sol +42 -0
- package/src/domains/facets/registrar/IL2Registrar.sol +57 -0
- package/src/domains/facets/registrar/L2RegistrarFacet.sol +127 -0
- package/src/domains/facets/registrar/L2RegistrarMod.sol +224 -0
- package/src/domains/hooks/DomainFeeHook.sol +212 -0
- package/src/factory/facets/architect/Architect.sol +48 -29
- package/src/factory/facets/architect/IArchitect.sol +2 -21
- package/src/factory/facets/architect/ImplementationStorage.sol +12 -20
- package/src/factory/facets/create/CreateSpace.sol +5 -0
- package/src/factory/facets/create/CreateSpaceBase.sol +32 -8
- package/src/factory/facets/create/ICreateSpace.sol +5 -0
- package/src/factory/facets/fee/FeeManagerFacet.sol +10 -0
- package/src/factory/facets/fee/FeeTypesLib.sol +3 -0
- package/src/river/registry/facets/node/INodeRegistry.sol +25 -0
- package/src/river/registry/facets/node/NodeRegistry.sol +53 -2
- package/src/river/registry/libraries/RegistryStorage.sol +5 -0
- package/src/spaces/facets/ProtocolFeeLib.sol +56 -1
- package/src/spaces/facets/proxy/SpaceProxyInitializer.sol +6 -8
- package/src/spaces/facets/xchain/SpaceEntitlementGated.sol +9 -0
- package/LICENSE.txt +0 -21
- package/scripts/bytecode-diff/README.md +0 -182
- package/scripts/deployments/utils/DeploySpaceProxyInitializer.s.sol +0 -28
- package/scripts/readme.md +0 -289
- package/src/diamond/readme.md +0 -50
- package/src/factory/SpaceFactoryInit.sol +0 -17
- package/src/factory/facets/architect/ArchitectBase.sol +0 -95
|
@@ -99,4 +99,9 @@ contract CreateSpaceFacet is ICreateSpace, PausableBase, ReentrancyGuard, Create
|
|
|
99
99
|
SpaceOptions memory spaceOptions = SpaceOptions({to: msg.sender});
|
|
100
100
|
return _createSpaceWithPrepayFromLegacy(spaceInfo, spaceOptions);
|
|
101
101
|
}
|
|
102
|
+
|
|
103
|
+
/// @inheritdoc ICreateSpace
|
|
104
|
+
function getProxyInitializer() external view returns (address) {
|
|
105
|
+
return _getProxyInitializer();
|
|
106
|
+
}
|
|
102
107
|
}
|
|
@@ -24,6 +24,7 @@ import {Validator} from "../../../utils/libraries/Validator.sol";
|
|
|
24
24
|
import {PricingModulesBase} from "../architect/pricing/PricingModulesBase.sol";
|
|
25
25
|
import {ArchitectStorage} from "../architect/ArchitectStorage.sol";
|
|
26
26
|
import {ImplementationStorage} from "../architect/ImplementationStorage.sol";
|
|
27
|
+
import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
|
|
27
28
|
|
|
28
29
|
// contracts
|
|
29
30
|
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
@@ -33,16 +34,21 @@ import {SpaceProxyInitializer} from "../../../spaces/facets/proxy/SpaceProxyInit
|
|
|
33
34
|
abstract contract CreateSpaceBase is IArchitectBase {
|
|
34
35
|
using StringSet for StringSet.Set;
|
|
35
36
|
using EnumerableSet for EnumerableSet.AddressSet;
|
|
37
|
+
using CustomRevert for bytes4;
|
|
36
38
|
|
|
37
39
|
address internal constant EVERYONE_ADDRESS = address(1);
|
|
38
40
|
string internal constant MINTER_ROLE = "Minter";
|
|
39
41
|
bytes1 internal constant CHANNEL_PREFIX = 0x20;
|
|
40
42
|
|
|
43
|
+
bytes32 private constant PROXY_INITIALIZER_INIT_CODE_HASH =
|
|
44
|
+
keccak256(type(SpaceProxyInitializer).creationCode);
|
|
45
|
+
bytes32 private constant PROXY_INITIALIZER_SALT = 0;
|
|
46
|
+
|
|
41
47
|
function _createSpaceWithPrepay(
|
|
42
48
|
CreateSpace calldata space,
|
|
43
49
|
SpaceOptions memory spaceOptions
|
|
44
50
|
) internal returns (address spaceAddress) {
|
|
45
|
-
if (msg.value > 0)
|
|
51
|
+
if (msg.value > 0) Architect__UnexpectedETH.selector.revertWith();
|
|
46
52
|
Validator.checkAddress(space.membership.settings.pricingModule);
|
|
47
53
|
Validator.checkAddress(spaceOptions.to);
|
|
48
54
|
|
|
@@ -61,7 +67,7 @@ abstract contract CreateSpaceBase is IArchitectBase {
|
|
|
61
67
|
CreateSpaceOld calldata space,
|
|
62
68
|
SpaceOptions memory spaceOptions
|
|
63
69
|
) internal returns (address spaceAddress) {
|
|
64
|
-
if (msg.value > 0)
|
|
70
|
+
if (msg.value > 0) Architect__UnexpectedETH.selector.revertWith();
|
|
65
71
|
Validator.checkAddress(space.membership.settings.pricingModule);
|
|
66
72
|
Validator.checkAddress(spaceOptions.to);
|
|
67
73
|
|
|
@@ -91,7 +97,7 @@ abstract contract CreateSpaceBase is IArchitectBase {
|
|
|
91
97
|
ChannelInfo calldata channel,
|
|
92
98
|
SpaceOptions memory spaceOptions
|
|
93
99
|
) private returns (address spaceAddress) {
|
|
94
|
-
ImplementationStorage.Layout storage ims = ImplementationStorage.
|
|
100
|
+
ImplementationStorage.Layout storage ims = ImplementationStorage.getStorage();
|
|
95
101
|
|
|
96
102
|
// get the token id of the next space
|
|
97
103
|
uint256 spaceTokenId = ims.spaceOwnerToken.nextTokenId();
|
|
@@ -309,7 +315,7 @@ abstract contract CreateSpaceBase is IArchitectBase {
|
|
|
309
315
|
ds.tokenIdBySpace[spaceAddress] = spaceTokenId;
|
|
310
316
|
}
|
|
311
317
|
// mint token to and transfer to Architect
|
|
312
|
-
ImplementationStorage.Layout storage ims = ImplementationStorage.
|
|
318
|
+
ImplementationStorage.Layout storage ims = ImplementationStorage.getStorage();
|
|
313
319
|
ims.spaceOwnerToken.mintSpace(
|
|
314
320
|
metadata.name,
|
|
315
321
|
metadata.uri,
|
|
@@ -334,23 +340,41 @@ abstract contract CreateSpaceBase is IArchitectBase {
|
|
|
334
340
|
|
|
335
341
|
function _verifyPricingModule(address pricingModule) internal view {
|
|
336
342
|
if (pricingModule == address(0) || !PricingModulesBase.isPricingModule(pricingModule)) {
|
|
337
|
-
|
|
343
|
+
Architect__InvalidPricingModule.selector.revertWith();
|
|
338
344
|
}
|
|
339
345
|
}
|
|
340
346
|
|
|
347
|
+
/// @dev Returns the deterministic CREATE2 address of SpaceProxyInitializer
|
|
348
|
+
function _getProxyInitializer() internal view returns (address) {
|
|
349
|
+
return
|
|
350
|
+
Factory.calculateDeploymentAddress(
|
|
351
|
+
PROXY_INITIALIZER_INIT_CODE_HASH,
|
|
352
|
+
PROXY_INITIALIZER_SALT
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/// @dev Deploys SpaceProxyInitializer via CREATE2 if not already deployed, returns its address
|
|
357
|
+
function _getOrDeployProxyInitializer() internal returns (address) {
|
|
358
|
+
address computed = _getProxyInitializer();
|
|
359
|
+
|
|
360
|
+
if (computed.code.length != 0) return computed;
|
|
361
|
+
|
|
362
|
+
return Factory.deploy(type(SpaceProxyInitializer).creationCode, PROXY_INITIALIZER_SALT);
|
|
363
|
+
}
|
|
364
|
+
|
|
341
365
|
function _getSpaceDeploymentInfo(
|
|
342
366
|
uint256 spaceTokenId,
|
|
343
367
|
IMembershipBase.Membership calldata membershipSettings,
|
|
344
368
|
SpaceOptions memory spaceOptions
|
|
345
|
-
) internal
|
|
369
|
+
) internal returns (bytes memory initCode, bytes32 salt) {
|
|
346
370
|
_verifyPricingModule(membershipSettings.pricingModule);
|
|
347
371
|
|
|
348
|
-
address spaceOwnerNFT = address(ImplementationStorage.
|
|
372
|
+
address spaceOwnerNFT = address(ImplementationStorage.getStorage().spaceOwnerToken);
|
|
349
373
|
|
|
350
374
|
// calculate salt
|
|
351
375
|
salt = keccak256(abi.encode(spaceTokenId, block.timestamp, block.number, spaceOwnerNFT));
|
|
352
376
|
|
|
353
|
-
address proxyInitializer =
|
|
377
|
+
address proxyInitializer = _getOrDeployProxyInitializer();
|
|
354
378
|
|
|
355
379
|
// calculate init code
|
|
356
380
|
initCode = bytes.concat(
|
|
@@ -67,4 +67,9 @@ interface ICreateSpace is IArchitectBase, ICreateSpaceBase {
|
|
|
67
67
|
function createSpaceWithPrepay(
|
|
68
68
|
CreateSpaceOld calldata spaceInfo
|
|
69
69
|
) external payable returns (address);
|
|
70
|
+
|
|
71
|
+
/// @notice Returns the address of the SpaceProxyInitializer contract
|
|
72
|
+
/// @return The deterministic CREATE2 address of the SpaceProxyInitializer
|
|
73
|
+
/// @dev The initializer is deployed on first space creation if not already deployed
|
|
74
|
+
function getProxyInitializer() external view returns (address);
|
|
70
75
|
}
|
|
@@ -135,5 +135,15 @@ contract FeeManagerFacet is
|
|
|
135
135
|
0.0005 ether,
|
|
136
136
|
true
|
|
137
137
|
);
|
|
138
|
+
|
|
139
|
+
// domain registration fee
|
|
140
|
+
_setFeeConfig(
|
|
141
|
+
FeeTypesLib.DOMAIN_REGISTRATION,
|
|
142
|
+
protocolRecipient,
|
|
143
|
+
FeeCalculationMethod.FIXED,
|
|
144
|
+
0,
|
|
145
|
+
0,
|
|
146
|
+
true
|
|
147
|
+
);
|
|
138
148
|
}
|
|
139
149
|
}
|
|
@@ -26,6 +26,9 @@ library FeeTypesLib {
|
|
|
26
26
|
/// @notice Fee for bot actions
|
|
27
27
|
bytes32 internal constant BOT_ACTION = keccak256("FEE_TYPE.BOT_ACTION");
|
|
28
28
|
|
|
29
|
+
/// @notice Fee for domain registration
|
|
30
|
+
bytes32 internal constant DOMAIN_REGISTRATION = keccak256("FEE_TYPE.DOMAIN_REGISTRATION");
|
|
31
|
+
|
|
29
32
|
/// @notice Generates fee type for membership based on currency
|
|
30
33
|
/// @param currency The payment currency address
|
|
31
34
|
/// @return The fee type identifier for the given currency
|
|
@@ -19,6 +19,7 @@ interface INodeRegistryBase {
|
|
|
19
19
|
event NodeStatusUpdated(address indexed nodeAddress, NodeStatus status);
|
|
20
20
|
event NodeUrlUpdated(address indexed nodeAddress, string url);
|
|
21
21
|
event NodeRemoved(address indexed nodeAddress);
|
|
22
|
+
event NodeCometBftPubKeyUpdated(address indexed nodeAddress, bytes32 cometBftPubKey);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
interface INodeRegistry is INodeRegistryBase {
|
|
@@ -66,4 +67,28 @@ interface INodeRegistry is INodeRegistryBase {
|
|
|
66
67
|
* a block.
|
|
67
68
|
*/
|
|
68
69
|
function getAllNodes() external view returns (Node[] memory);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @notice Backfill permanent indices for all existing nodes that don't have one assigned.
|
|
73
|
+
* @dev This should be called once after the contract upgrade. It assigns sequential indices
|
|
74
|
+
* starting from 1 to all nodes in their current array order. Subsequent registrations will
|
|
75
|
+
* continue from the last assigned index.
|
|
76
|
+
* Function can only be called once and reverts with ALREADY_EXISTS on subsequent calls.
|
|
77
|
+
*/
|
|
78
|
+
function backfillPermanentIndices() external;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @notice Set or update the CometBFT public key for a node.
|
|
82
|
+
* @dev Can only be called by the node itself.
|
|
83
|
+
* @param nodeAddress The address of the node to update
|
|
84
|
+
* @param cometBftPubKey The 32-byte CometBFT public key
|
|
85
|
+
*/
|
|
86
|
+
function setNodeCometBftPubKey(address nodeAddress, bytes32 cometBftPubKey) external;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @notice Get the last assigned permanent node index.
|
|
90
|
+
* @dev Returns 0 if backfill has not been called yet.
|
|
91
|
+
* @return The last assigned permanent node index
|
|
92
|
+
*/
|
|
93
|
+
function getLastNodeIndex() external view returns (uint32);
|
|
69
94
|
}
|
|
@@ -12,9 +12,10 @@ import {RiverRegistryErrors} from "src/river/registry/libraries/RegistryErrors.s
|
|
|
12
12
|
import {CustomRevert} from "src/utils/libraries/CustomRevert.sol";
|
|
13
13
|
|
|
14
14
|
// contracts
|
|
15
|
+
import {OwnableBase} from "@towns-protocol/diamond/src/facets/ownable/OwnableBase.sol";
|
|
15
16
|
import {RegistryModifiers} from "src/river/registry/libraries/RegistryStorage.sol";
|
|
16
17
|
|
|
17
|
-
contract NodeRegistry is INodeRegistry, RegistryModifiers {
|
|
18
|
+
contract NodeRegistry is INodeRegistry, RegistryModifiers, OwnableBase {
|
|
18
19
|
using EnumerableSet for EnumerableSet.AddressSet;
|
|
19
20
|
using CustomRevert for string;
|
|
20
21
|
|
|
@@ -32,16 +33,25 @@ contract NodeRegistry is INodeRegistry, RegistryModifiers {
|
|
|
32
33
|
RiverRegistryErrors.ALREADY_EXISTS.revertWith();
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
// Assign permanent index if backfill has been called (lastNodeIndex > 0)
|
|
37
|
+
uint32 permanentIndex = 0;
|
|
38
|
+
if (ds.lastNodeIndex > 0) {
|
|
39
|
+
permanentIndex = ++ds.lastNodeIndex;
|
|
40
|
+
}
|
|
41
|
+
|
|
35
42
|
Node memory newNode = Node({
|
|
36
43
|
nodeAddress: nodeAddress,
|
|
37
44
|
url: url,
|
|
38
45
|
status: status,
|
|
39
|
-
operator: msg.sender
|
|
46
|
+
operator: msg.sender,
|
|
47
|
+
permanentIndex: permanentIndex,
|
|
48
|
+
cometBftPubKey: bytes32(0)
|
|
40
49
|
});
|
|
41
50
|
|
|
42
51
|
ds.nodes.add(nodeAddress); // TODO: remove this line
|
|
43
52
|
ds.nodeByAddress[nodeAddress] = newNode;
|
|
44
53
|
|
|
54
|
+
// TODO: Consider adding permanentIndex to the event
|
|
45
55
|
emit NodeAdded(nodeAddress, msg.sender, url, status);
|
|
46
56
|
}
|
|
47
57
|
|
|
@@ -123,6 +133,47 @@ contract NodeRegistry is INodeRegistry, RegistryModifiers {
|
|
|
123
133
|
return nodes;
|
|
124
134
|
}
|
|
125
135
|
|
|
136
|
+
function backfillPermanentIndices() external onlyOwner {
|
|
137
|
+
// Can only be called once - after execution, lastNodeIndex > 0
|
|
138
|
+
if (ds.lastNodeIndex > 0) {
|
|
139
|
+
RiverRegistryErrors.ALREADY_EXISTS.revertWith();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
address[] memory nodeAddresses = ds.nodes.values();
|
|
143
|
+
uint32 currentIndex;
|
|
144
|
+
|
|
145
|
+
for (uint256 i; i < nodeAddresses.length; ++i) {
|
|
146
|
+
Node storage node = ds.nodeByAddress[nodeAddresses[i]];
|
|
147
|
+
|
|
148
|
+
if (node.permanentIndex != 0) {
|
|
149
|
+
RiverRegistryErrors.BAD_ARG.revertWith();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
node.permanentIndex = ++currentIndex;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
ds.lastNodeIndex = currentIndex;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function setNodeCometBftPubKey(
|
|
159
|
+
address nodeAddress,
|
|
160
|
+
bytes32 cometBftPubKey
|
|
161
|
+
) external onlyNode(nodeAddress) {
|
|
162
|
+
// Only the node itself can set its CometBFT public key
|
|
163
|
+
if (msg.sender != nodeAddress) {
|
|
164
|
+
RiverRegistryErrors.BAD_AUTH.revertWith();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
Node storage node = ds.nodeByAddress[nodeAddress];
|
|
168
|
+
node.cometBftPubKey = cometBftPubKey;
|
|
169
|
+
|
|
170
|
+
emit NodeCometBftPubKeyUpdated(nodeAddress, cometBftPubKey);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function getLastNodeIndex() external view returns (uint32) {
|
|
174
|
+
return ds.lastNodeIndex;
|
|
175
|
+
}
|
|
176
|
+
|
|
126
177
|
function _checkNodeStatusTransionAllowed(NodeStatus from, NodeStatus to) internal pure {
|
|
127
178
|
if (
|
|
128
179
|
from == NodeStatus.NotInitialized ||
|
|
@@ -49,6 +49,8 @@ struct Node {
|
|
|
49
49
|
string url; // dynamically sized, points to a separate location
|
|
50
50
|
address nodeAddress; // 20 bytes
|
|
51
51
|
address operator; // 20 bytes
|
|
52
|
+
uint32 permanentIndex; // 4 bytes, permanent index assigned to this node. 0 = not initialized
|
|
53
|
+
bytes32 cometBftPubKey; // 32 bytes, CometBFT public key for consensus
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -88,6 +90,9 @@ struct AppStorage {
|
|
|
88
90
|
uint256 deprecatedSlot;
|
|
89
91
|
// Map of node address to its stream ids
|
|
90
92
|
mapping(address => EnumerableSet.Bytes32Set) streamIdsByNode;
|
|
93
|
+
// Last assigned permanent node index. Used to assign unique indices to new nodes.
|
|
94
|
+
// 0 means backfill has not been called yet; after backfill, this tracks the highest assigned index.
|
|
95
|
+
uint32 lastNodeIndex;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
library RiverRegistryStorage {
|
|
@@ -23,6 +23,27 @@ library ProtocolFeeLib {
|
|
|
23
23
|
address currency,
|
|
24
24
|
uint256 amount,
|
|
25
25
|
uint256 expectedFee
|
|
26
|
+
) internal returns (uint256 protocolFee) {
|
|
27
|
+
return charge(spaceFactory, feeType, user, currency, amount, expectedFee, "");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// @notice Charges protocol fee via FeeManager with ERC20 approval handling and extra data
|
|
31
|
+
/// @param spaceFactory The FeeManager address
|
|
32
|
+
/// @param feeType The type of fee being charged
|
|
33
|
+
/// @param user The user paying the fee
|
|
34
|
+
/// @param currency The payment currency (NATIVE_TOKEN or ERC20)
|
|
35
|
+
/// @param amount The base amount for fee calculation
|
|
36
|
+
/// @param expectedFee The pre-calculated expected fee
|
|
37
|
+
/// @param extraData Additional data for fee calculation (e.g., label length for domain registration)
|
|
38
|
+
/// @return protocolFee The actual fee charged
|
|
39
|
+
function charge(
|
|
40
|
+
address spaceFactory,
|
|
41
|
+
bytes32 feeType,
|
|
42
|
+
address user,
|
|
43
|
+
address currency,
|
|
44
|
+
uint256 amount,
|
|
45
|
+
uint256 expectedFee,
|
|
46
|
+
bytes memory extraData
|
|
26
47
|
) internal returns (uint256 protocolFee) {
|
|
27
48
|
if (expectedFee == 0) return 0;
|
|
28
49
|
|
|
@@ -35,9 +56,43 @@ library ProtocolFeeLib {
|
|
|
35
56
|
amount,
|
|
36
57
|
currency,
|
|
37
58
|
expectedFee,
|
|
38
|
-
|
|
59
|
+
extraData
|
|
39
60
|
);
|
|
40
61
|
|
|
41
62
|
if (!isNative) currency.safeApprove(spaceFactory, 0);
|
|
42
63
|
}
|
|
64
|
+
|
|
65
|
+
/// @notice Charges protocol fee via FeeManager, always calling chargeFee even when expectedFee is 0
|
|
66
|
+
/// @dev Use this when the fee hook needs to track calls regardless of fee amount (e.g., domain registration count)
|
|
67
|
+
/// @param spaceFactory The FeeManager address
|
|
68
|
+
/// @param feeType The type of fee being charged
|
|
69
|
+
/// @param user The user paying the fee
|
|
70
|
+
/// @param currency The payment currency (NATIVE_TOKEN or ERC20)
|
|
71
|
+
/// @param amount The base amount for fee calculation
|
|
72
|
+
/// @param expectedFee The pre-calculated expected fee
|
|
73
|
+
/// @param extraData Additional data for fee calculation
|
|
74
|
+
/// @return protocolFee The actual fee charged
|
|
75
|
+
function chargeAlways(
|
|
76
|
+
address spaceFactory,
|
|
77
|
+
bytes32 feeType,
|
|
78
|
+
address user,
|
|
79
|
+
address currency,
|
|
80
|
+
uint256 amount,
|
|
81
|
+
uint256 expectedFee,
|
|
82
|
+
bytes memory extraData
|
|
83
|
+
) internal returns (uint256 protocolFee) {
|
|
84
|
+
bool isNative = currency == CurrencyTransfer.NATIVE_TOKEN;
|
|
85
|
+
if (!isNative && expectedFee > 0) currency.safeApproveWithRetry(spaceFactory, expectedFee);
|
|
86
|
+
|
|
87
|
+
protocolFee = IFeeManager(spaceFactory).chargeFee{value: isNative ? expectedFee : 0}(
|
|
88
|
+
feeType,
|
|
89
|
+
user,
|
|
90
|
+
amount,
|
|
91
|
+
currency,
|
|
92
|
+
expectedFee,
|
|
93
|
+
extraData
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (!isNative && expectedFee > 0) currency.safeApprove(spaceFactory, 0);
|
|
97
|
+
}
|
|
43
98
|
}
|
|
@@ -2,22 +2,20 @@
|
|
|
2
2
|
pragma solidity ^0.8.23;
|
|
3
3
|
|
|
4
4
|
// interfaces
|
|
5
|
-
|
|
6
5
|
import {IERC173} from "@towns-protocol/diamond/src/facets/ownable/IERC173.sol";
|
|
7
|
-
import {IERC5643} from "
|
|
8
|
-
import {IMembership} from "
|
|
9
|
-
import {ISpaceProxyInitializer} from "
|
|
6
|
+
import {IERC5643} from "../../../diamond/facets/token/ERC5643/IERC5643.sol";
|
|
7
|
+
import {IMembership} from "../membership/IMembership.sol";
|
|
8
|
+
import {ISpaceProxyInitializer} from "./ISpaceProxyInitializer.sol";
|
|
10
9
|
|
|
11
10
|
// libraries
|
|
12
11
|
|
|
13
12
|
// contracts
|
|
14
|
-
|
|
15
13
|
import {Initializable} from "@towns-protocol/diamond/src/facets/initializable/Initializable.sol";
|
|
16
14
|
import {IntrospectionBase} from "@towns-protocol/diamond/src/facets/introspection/IntrospectionBase.sol";
|
|
17
15
|
import {TokenOwnableBase} from "@towns-protocol/diamond/src/facets/ownable/token/TokenOwnableBase.sol";
|
|
18
|
-
import {ERC721ABase} from "
|
|
19
|
-
import {EntitlementGatedBase} from "
|
|
20
|
-
import {MembershipBase} from "
|
|
16
|
+
import {ERC721ABase} from "../../../diamond/facets/token/ERC721A/ERC721ABase.sol";
|
|
17
|
+
import {EntitlementGatedBase} from "../gated/EntitlementGatedBase.sol";
|
|
18
|
+
import {MembershipBase} from "../membership/MembershipBase.sol";
|
|
21
19
|
|
|
22
20
|
contract SpaceProxyInitializer is
|
|
23
21
|
ISpaceProxyInitializer,
|
|
@@ -29,6 +29,15 @@ contract SpaceEntitlementGated is MembershipJoin, EntitlementGated {
|
|
|
29
29
|
);
|
|
30
30
|
|
|
31
31
|
if (result == NodeVoteStatus.PASSED) {
|
|
32
|
+
// Re-validate supply cap before minting to prevent over-minting from
|
|
33
|
+
// concurrent crosschain join requests that were all accepted when under
|
|
34
|
+
// the cap but would exceed it if all finalized
|
|
35
|
+
uint256 membershipSupplyLimit = _getMembershipSupplyLimit();
|
|
36
|
+
if (membershipSupplyLimit != 0 && _totalSupply() >= membershipSupplyLimit) {
|
|
37
|
+
_rejectMembership(transactionId, receiver);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
PricingDetails memory joinDetails = _getPricingDetails();
|
|
33
42
|
|
|
34
43
|
if (!joinDetails.shouldCharge) {
|
package/LICENSE.txt
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 River Association
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# Bytecode-Diff Tool
|
|
2
|
-
|
|
3
|
-
Bytecode-Diff is a tool to retrieve and display contract bytecode diff for Base deployed contracts and Solidity source compiled bytecode compiled with forge. It provides functionality to run source code diffs or remote bytecode diffs and create reports that detail changes between two compiled bytecode versions of contracts.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
- Go 1.22 or later
|
|
8
|
-
- Base RPC Provider URL
|
|
9
|
-
- River Chain RPC Provider URL
|
|
10
|
-
- Basescan API Key
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
### Local Source Code Diff
|
|
15
|
-
|
|
16
|
-
Compile contracts with forge and run source code diff comparing nearest commit report with checked out commit.
|
|
17
|
-
|
|
18
|
-
The basic command structure is:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
# ensure contracts are compiled with forge
|
|
22
|
-
cd ../../packages/contracts
|
|
23
|
-
make build
|
|
24
|
-
# disable go.work file since bytecode-diff is not a module in parent go workspace
|
|
25
|
-
go mod download
|
|
26
|
-
# run source diff from checked out commitSha compared nearest commit with a source diff report in SOURCE_DIFF_DIR
|
|
27
|
-
GOWORK=off go run main.go -v -s
|
|
28
|
-
|
|
29
|
-
# write report with contract addresses, their keccak256 compilaed bytecode hash under two keys, existing and updated.
|
|
30
|
-
➜ bytecode-diff ✗ yq eval '.existing' source-diffs/00adc44f_08292024_5.yaml
|
|
31
|
-
Architect: 0xd291e489716f2c9cfc2e2c6047ce777159969943c85d09c51aaf7bbad10f7c13
|
|
32
|
-
ArchitectBase: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
|
|
33
|
-
ArchitectStorage: 0x86159d997458669c4df8af2da4b5ce9ca742099a3f854c5eb3e718e16a74e4da
|
|
34
|
-
Banning: 0xde1354882fd30088cce4b00ff720a6dbc8c9f25653477c6ee99e20e17edb6068
|
|
35
|
-
BanningBase: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
|
|
36
|
-
BanningStorage: 0x86159d997458669c4df8af2da4b5ce9ca742099a3f854c5eb3e718e16a74e4da
|
|
37
|
-
ChannelBase: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
|
|
38
|
-
...
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Run pairwise remote bytecode diff on facets deployed to two networks
|
|
42
|
-
|
|
43
|
-
Runs bytecode diff from deployed facets for diamonds in alpha, beta, and omega environments as per source coordinates of diamonds for each environment.
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
# compare omega against beta facets and facet selectors
|
|
47
|
-
GOWORK=off go run ./main.go beta omega -v
|
|
48
|
-
|
|
49
|
-
# output facet implementation changes by facet or selectors that are missing from omega
|
|
50
|
-
➜ bytecode-diff git:(jt/net-62-contract-differ) ✗ yq eval deployed-diffs/facet_diff_090324_18.yaml
|
|
51
|
-
diamonds:
|
|
52
|
-
- name: spaceOwner
|
|
53
|
-
source: beta
|
|
54
|
-
target: omega
|
|
55
|
-
facets:
|
|
56
|
-
- sourceContractName: ""
|
|
57
|
-
sourceFacetAddress: 0xfa98a1648761e494fc7d6efe5a06e357a76bd6fb
|
|
58
|
-
selectorsDiff:
|
|
59
|
-
- "0x3953801b"
|
|
60
|
-
- "0x91de4a83"
|
|
61
|
-
sourceBytecodeHash: 0xf86d9dbe53c89e14fa69cde925cca02b6efad519fe172f7b04d9515d7700a59b
|
|
62
|
-
sourceVerified: false
|
|
63
|
-
targetVerified: false
|
|
64
|
-
- sourceContractName: SpaceOwner
|
|
65
|
-
sourceFacetAddress: 0x30c912d8ceb9793e4cd240862acfd0e6c4436c52
|
|
66
|
-
targetContractAddresses:
|
|
67
|
-
- 0x63bC35259Ac32DF43Fba3b890F0F74951451976A
|
|
68
|
-
- 0xe7EB1313f0E7076616534225e16E971B72b50C42
|
|
69
|
-
selectorsDiff: []
|
|
70
|
-
sourceBytecodeHash: 0x461b53ab37fd24283ecd63eb0d4e71bd554a266036c73caf6d2ac39c435e7732
|
|
71
|
-
targetBytecodeHashes:
|
|
72
|
-
- 0x86d20161a13671a6138b80551e94dd8c1638bc5151807ff2194aa1e50cdb3cac
|
|
73
|
-
- 0xff0a94e93a4f4f6ee0ecd0d0e469e55ca40f1ab6c10e6af9da5b2b597f32b178
|
|
74
|
-
sourceVerified: true
|
|
75
|
-
targetVerified: true
|
|
76
|
-
- sourceContractName: ""
|
|
77
|
-
sourceFacetAddress: 0xdba2ce6125cc6b7f93c63d181a0780d5b421940b
|
|
78
|
-
selectorsDiff:
|
|
79
|
-
- "0x0d653654"
|
|
80
|
-
- "0x466a18de"
|
|
81
|
-
sourceBytecodeHash: 0x583c2852056f90c96ed1cab935489f644b8ef564e0a7f11564925d07cf3bc593
|
|
82
|
-
sourceVerified: false
|
|
83
|
-
targetVerified: false
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Run keccak256 hash generation on deployed contracts
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
GOWORK=off go run main.go add-hashes beta deployed-diffs/facet_diff_090624_1.yaml
|
|
91
|
-
|
|
92
|
-
# output to new yaml file suffixed with _hashed.yaml including bytecodeHash for each contract in deployments section
|
|
93
|
-
➜ bytecode-diff git:(jt/net-62-upgrade-script-2) ✗ yq e '.deployments' deployed-diffs/facet_diff_090624_1_hashed.yaml
|
|
94
|
-
Architect:
|
|
95
|
-
address: 0xa18a3df4f63cdcae943d9c76730adf2812388de4
|
|
96
|
-
baseScanLink: https://sepolia.basescan.org/tx/0x4280ef1300fe001e7d85e7495eba13fc99be53ee7a7060e753d466f8bebf1622
|
|
97
|
-
bytecodeHash: 0x20d0a86e9ea31a39663285aacfe88705983520a4482a7bac5ada891c9adfe090
|
|
98
|
-
deploymentDate: 2024-09-06 19:04
|
|
99
|
-
transactionHash: 0x4280ef1300fe001e7d85e7495eba13fc99be53ee7a7060e753d466f8bebf1622
|
|
100
|
-
Banning:
|
|
101
|
-
address: 0x4d88d1fbba6ce6bcdb4381549ee0b7c0d2b56919
|
|
102
|
-
baseScanLink: https://sepolia.basescan.org/tx/0x4ccbaf9750bcd0971975e73a24b05f1c51d4703cf72a406356c79eb54de9c33c
|
|
103
|
-
bytecodeHash: 0xa2ce3e77ba060ff1d59ed384e1c6c5788f308ad8bbbef612eb3e5de4e1d79de8
|
|
104
|
-
deploymentDate: 2024-09-06 19:05
|
|
105
|
-
transactionHash: 0x4ccbaf9750bcd0971975e73a24b05f1c51d4703cf72a406356c79eb54de9c33c
|
|
106
|
-
...
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Flags
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
➜ bytecode-diff ✗ GOWORK=off go run ./main.go --help
|
|
113
|
-
A tool to retrieve and display contract bytecode diff for Base
|
|
114
|
-
|
|
115
|
-
Usage:
|
|
116
|
-
bytecode-diff [source_environment] [target_environment] [flags]
|
|
117
|
-
|
|
118
|
-
Flags:
|
|
119
|
-
-b, --base-rpc string Base RPC provider URL
|
|
120
|
-
--base-sepolia-rpc string Base Sepolia RPC provider URL
|
|
121
|
-
--compiled-facets string Path to compiled facets
|
|
122
|
-
--deployments string Path to deployments directory (default "../../packages/contracts/deployments")
|
|
123
|
-
--facets string Path to facet source files
|
|
124
|
-
-h, --help help for bytecode-diff
|
|
125
|
-
--log-level string Set the logging level (debug, info, warn, error) (default "info")
|
|
126
|
-
--report-out-dir string Path to report output directory (default "deployed-diffs")
|
|
127
|
-
--source-diff-log string Path to diff log file (default "source-diffs")
|
|
128
|
-
-s, --source-diff-only Run source code diff
|
|
129
|
-
-v, --verbose Enable verbose output
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Environment Variables
|
|
133
|
-
|
|
134
|
-
You can also set the following environment variables instead of using flags:
|
|
135
|
-
|
|
136
|
-
- `BASE_RPC_URL`: Base RPC provider URL
|
|
137
|
-
- `BASE_SEPOLIA_RPC_URL`: Base Sepolia RPC provider URL
|
|
138
|
-
- `FACET_SOURCE_PATH`: Path to facet source files
|
|
139
|
-
- `ETHERSCAN_API_KEY`: Your API key for Etherscan.
|
|
140
|
-
- `COMPILED_FACETS_PATH`: (Optional) Path to compiled facets
|
|
141
|
-
- `DEPLOYMENTS_PATH`: (Optional) Path to deployed contracts
|
|
142
|
-
- `REPORT_OUT_DIR`: (Optional) Path to report output directory
|
|
143
|
-
- `SOURCE_DIFF_DIR`: (Optional) Path to source diff reports
|
|
144
|
-
|
|
145
|
-
## Examples
|
|
146
|
-
|
|
147
|
-
1. Run source code diff with all parameters specified via flags:
|
|
148
|
-
|
|
149
|
-
```
|
|
150
|
-
./bytecode-diff --source-diff-only \
|
|
151
|
-
--source-diff-dir /path/to/source-diff-reports \
|
|
152
|
-
--facets /path/to/facet/sources \
|
|
153
|
-
--compiled-facets /path/to/compiled/facets \
|
|
154
|
-
--report-out-dir /path/to/report/output \
|
|
155
|
-
--verbose
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
2. Run source code diff using environment variables:
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
export SOURCE_DIFF_DIR=/path/to/source_diff.log
|
|
162
|
-
export FACET_SOURCE_PATH=/path/to/facet/sources
|
|
163
|
-
export COMPILED_FACETS_PATH=/path/to/compiled/facets
|
|
164
|
-
export REPORT_OUT_DIR=/path/to/report/output
|
|
165
|
-
|
|
166
|
-
./bytecode-diff -s --verbose
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
3. Run source code diff with r/w to remote s3 bucket:
|
|
170
|
-
|
|
171
|
-
```bash
|
|
172
|
-
export AWS_ACCESS_KEY_ID=<your-access-key-id>
|
|
173
|
-
export AWS_SECRET_ACCESS_KEY=<your-secret-access-key>
|
|
174
|
-
export SOURCE_DIFF_DIR=s3://bucket/path
|
|
175
|
-
./bytecode-diff -s --verbose
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## Notes
|
|
179
|
-
|
|
180
|
-
- If a `.env` file is present in the same directory as the script, it will be loaded automatically.
|
|
181
|
-
- When running source code diff, all required paths must be provided either via flags or environment variables.
|
|
182
|
-
- Use the `--verbose` flag for more detailed output during execution.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.23;
|
|
3
|
-
|
|
4
|
-
// interfaces
|
|
5
|
-
|
|
6
|
-
// libraries
|
|
7
|
-
|
|
8
|
-
// contracts
|
|
9
|
-
import {SpaceProxyInitializer} from "src/spaces/facets/proxy/SpaceProxyInitializer.sol";
|
|
10
|
-
import {Deployer} from "scripts/common/Deployer.s.sol";
|
|
11
|
-
|
|
12
|
-
contract DeploySpaceProxyInitializer is Deployer {
|
|
13
|
-
function versionName() public pure override returns (string memory) {
|
|
14
|
-
return "utils/spaceProxyInitializer";
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function __deploy(address deployer) internal override returns (address) {
|
|
18
|
-
bytes32 salt = bytes32(uint256(1));
|
|
19
|
-
bytes32 initCodeHash = hashInitCode(type(SpaceProxyInitializer).creationCode);
|
|
20
|
-
address soonToBe = vm.computeCreate2Address(salt, initCodeHash);
|
|
21
|
-
|
|
22
|
-
vm.broadcast(deployer);
|
|
23
|
-
SpaceProxyInitializer initializer = new SpaceProxyInitializer{salt: salt}();
|
|
24
|
-
|
|
25
|
-
require(address(initializer) == soonToBe, "address mismatch");
|
|
26
|
-
return address(initializer);
|
|
27
|
-
}
|
|
28
|
-
}
|