@towns-protocol/contracts 0.0.302

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 (396) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +206 -0
  3. package/docs/permitAndStake_integration_guide.md +266 -0
  4. package/docs/swap_integration_guide.md +591 -0
  5. package/package.json +57 -0
  6. package/scripts/common/DeployBase.s.sol +26 -0
  7. package/scripts/common/DeployFacet.s.sol +7 -0
  8. package/scripts/common/Deployer.s.sol +33 -0
  9. package/scripts/common/Interaction.s.sol +51 -0
  10. package/scripts/deployments/diamonds/DeployAppRegistry.s.sol +168 -0
  11. package/scripts/deployments/diamonds/DeployBaseRegistry.s.sol +263 -0
  12. package/scripts/deployments/diamonds/DeployRiverAirdrop.s.sol +203 -0
  13. package/scripts/deployments/diamonds/DeployRiverMigration.s.sol +129 -0
  14. package/scripts/deployments/diamonds/DeployRiverRegistry.s.sol +175 -0
  15. package/scripts/deployments/diamonds/DeploySpace.s.sol +285 -0
  16. package/scripts/deployments/diamonds/DeploySpaceFactory.s.sol +416 -0
  17. package/scripts/deployments/diamonds/DeploySpaceOwner.s.sol +183 -0
  18. package/scripts/deployments/diamonds/DeploySwapRouter.s.sol +176 -0
  19. package/scripts/deployments/diamonds/IDiamondInitHelper.sol +11 -0
  20. package/scripts/deployments/facets/DeployAppAccount.s.sol +51 -0
  21. package/scripts/deployments/facets/DeployAppRegistryFacet.s.sol +69 -0
  22. package/scripts/deployments/facets/DeployArchitect.s.sol +51 -0
  23. package/scripts/deployments/facets/DeployAttestationRegistry.s.sol +36 -0
  24. package/scripts/deployments/facets/DeployBanning.s.sol +30 -0
  25. package/scripts/deployments/facets/DeployChannels.s.sol +35 -0
  26. package/scripts/deployments/facets/DeployCreateSpace.s.sol +42 -0
  27. package/scripts/deployments/facets/DeployDropFacet.s.sol +49 -0
  28. package/scripts/deployments/facets/DeployERC721A.s.sol +48 -0
  29. package/scripts/deployments/facets/DeployERC721ANonTransferable.s.sol +49 -0
  30. package/scripts/deployments/facets/DeployERC721AQueryable.s.sol +30 -0
  31. package/scripts/deployments/facets/DeployEntitlementChecker.s.sol +49 -0
  32. package/scripts/deployments/facets/DeployEntitlementDataQueryable.s.sol +29 -0
  33. package/scripts/deployments/facets/DeployEntitlementsManager.s.sol +33 -0
  34. package/scripts/deployments/facets/DeployExecutorFacet.s.sol +60 -0
  35. package/scripts/deployments/facets/DeployFeatureManager.s.sol +38 -0
  36. package/scripts/deployments/facets/DeployGuardianFacet.s.sol +39 -0
  37. package/scripts/deployments/facets/DeployImplementationRegistry.s.sol +36 -0
  38. package/scripts/deployments/facets/DeployMainnetDelegation.s.sol +43 -0
  39. package/scripts/deployments/facets/DeployMembership.s.sol +77 -0
  40. package/scripts/deployments/facets/DeployMembershipMetadata.s.sol +30 -0
  41. package/scripts/deployments/facets/DeployMembershipToken.s.sol +47 -0
  42. package/scripts/deployments/facets/DeployMerkleAirdrop.s.sol +37 -0
  43. package/scripts/deployments/facets/DeployMetadata.s.sol +39 -0
  44. package/scripts/deployments/facets/DeployMockLegacyArchitect.s.sol +33 -0
  45. package/scripts/deployments/facets/DeployNodeOperator.s.sol +49 -0
  46. package/scripts/deployments/facets/DeployNodeRegistry.s.sol +37 -0
  47. package/scripts/deployments/facets/DeployOperatorRegistry.s.sol +36 -0
  48. package/scripts/deployments/facets/DeployPartnerRegistry.s.sol +41 -0
  49. package/scripts/deployments/facets/DeployPlatformRequirements.s.sol +75 -0
  50. package/scripts/deployments/facets/DeployPrepayFacet.s.sol +31 -0
  51. package/scripts/deployments/facets/DeployPricingModules.s.sol +36 -0
  52. package/scripts/deployments/facets/DeployReferrals.s.sol +34 -0
  53. package/scripts/deployments/facets/DeployReviewFacet.s.sol +31 -0
  54. package/scripts/deployments/facets/DeployRewardsDistributionV2.s.sol +76 -0
  55. package/scripts/deployments/facets/DeployRiverConfig.s.sol +41 -0
  56. package/scripts/deployments/facets/DeployRoles.s.sol +48 -0
  57. package/scripts/deployments/facets/DeploySchemaRegistry.s.sol +35 -0
  58. package/scripts/deployments/facets/DeploySignerFacet.s.sol +47 -0
  59. package/scripts/deployments/facets/DeploySimpleApp.s.sol +10 -0
  60. package/scripts/deployments/facets/DeploySpaceDelegation.s.sol +43 -0
  61. package/scripts/deployments/facets/DeploySpaceEntitlementGated.s.sol +31 -0
  62. package/scripts/deployments/facets/DeploySpaceFactoryInit.s.sol +33 -0
  63. package/scripts/deployments/facets/DeploySpaceOwnerFacet.s.sol +71 -0
  64. package/scripts/deployments/facets/DeployStreamRegistry.s.sol +50 -0
  65. package/scripts/deployments/facets/DeploySwapFacet.s.sol +33 -0
  66. package/scripts/deployments/facets/DeploySwapRouterFacet.s.sol +38 -0
  67. package/scripts/deployments/facets/DeployTipping.s.sol +31 -0
  68. package/scripts/deployments/facets/DeployTokenMigration.s.sol +40 -0
  69. package/scripts/deployments/facets/DeployTownsPoints.s.sol +53 -0
  70. package/scripts/deployments/facets/DeployTreasury.s.sol +30 -0
  71. package/scripts/deployments/facets/DeployUpgradeableBeacon.s.sol +34 -0
  72. package/scripts/deployments/facets/DeployWalletLink.s.sol +56 -0
  73. package/scripts/deployments/facets/DeployXChain.s.sol +35 -0
  74. package/scripts/deployments/utils/DeployAccountFactory.s.sol +40 -0
  75. package/scripts/deployments/utils/DeployEntitlementGatedExample.s.sol +23 -0
  76. package/scripts/deployments/utils/DeployEntrypoint.s.sol +28 -0
  77. package/scripts/deployments/utils/DeployMember.s.sol +95 -0
  78. package/scripts/deployments/utils/DeployMockDiamond.s.sol +7 -0
  79. package/scripts/deployments/utils/DeployMockERC20.s.sol +24 -0
  80. package/scripts/deployments/utils/DeployMockERC721A.s.sol +45 -0
  81. package/scripts/deployments/utils/DeployMockLegacyMembership.s.sol +29 -0
  82. package/scripts/deployments/utils/DeployMockMessenger.s.sol +42 -0
  83. package/scripts/deployments/utils/DeployMockNFT.s.sol +86 -0
  84. package/scripts/deployments/utils/DeployPoapEntitlement.s.sol +16 -0
  85. package/scripts/deployments/utils/DeployProxyBatchDelegation.s.sol +112 -0
  86. package/scripts/deployments/utils/DeploySpaceProxyInitializer.s.sol +28 -0
  87. package/scripts/deployments/utils/DeployTieredLogPricingV2.s.sol +23 -0
  88. package/scripts/deployments/utils/DeployTieredLogPricingV3.s.sol +23 -0
  89. package/scripts/deployments/utils/DeployTownsBase.s.sol +95 -0
  90. package/scripts/deployments/utils/DeployTownsMainnet.s.sol +66 -0
  91. package/scripts/deployments/utils/DeployTownsMulti.s.sol +53 -0
  92. package/scripts/deployments/utils/DeployWrappedTowns.s.sol +52 -0
  93. package/scripts/deployments/utils/LibLayerZeroValues.sol +34 -0
  94. package/scripts/deployments/utils/pricing/TieredLogPricing.s.sol +45 -0
  95. package/scripts/interactions/InteractAirdrop.s.sol +57 -0
  96. package/scripts/interactions/InteractAlphaPost.s.sol +32 -0
  97. package/scripts/interactions/InteractAlphaSparse.s.sol +173 -0
  98. package/scripts/interactions/InteractBaseAlpha.s.sol +84 -0
  99. package/scripts/interactions/InteractBaseBridge.s.sol +48 -0
  100. package/scripts/interactions/InteractBridgeLayerZero.s.sol +102 -0
  101. package/scripts/interactions/InteractClaimCondition.s.sol +56 -0
  102. package/scripts/interactions/InteractCreateSpace.s.sol +50 -0
  103. package/scripts/interactions/InteractDiamondCut.s.sol +47 -0
  104. package/scripts/interactions/InteractDropFacet.s.sol +32 -0
  105. package/scripts/interactions/InteractEnableNewSnapshotFormat.s.sol +27 -0
  106. package/scripts/interactions/InteractEnableNode2NodeAuth.s.sol +27 -0
  107. package/scripts/interactions/InteractMembership.s.sol +42 -0
  108. package/scripts/interactions/InteractMockERC721A.s.sol +20 -0
  109. package/scripts/interactions/InteractNodeOperators.s.sol +41 -0
  110. package/scripts/interactions/InteractPostDeploy.s.sol +59 -0
  111. package/scripts/interactions/InteractPrepay.s.sol +30 -0
  112. package/scripts/interactions/InteractRegisterApp.s.sol +61 -0
  113. package/scripts/interactions/InteractRiverAlpha.s.sol +30 -0
  114. package/scripts/interactions/InteractRiverAlphaSparse.s.sol +117 -0
  115. package/scripts/interactions/InteractRiverMainnet.s.sol +27 -0
  116. package/scripts/interactions/InteractRiverRegistry.s.sol +36 -0
  117. package/scripts/interactions/InteractRiverRegistrySetBlocklist.s.sol +30 -0
  118. package/scripts/interactions/InteractRiverRegistrySetFreq.s.sol +27 -0
  119. package/scripts/interactions/InteractRiverRegistrySetRepl.s.sol +30 -0
  120. package/scripts/interactions/InteractSetDefaultUri.s.sol +20 -0
  121. package/scripts/interactions/InteractSetDefaultUriLocalhost.s.sol +19 -0
  122. package/scripts/interactions/InteractTransferOwnership.s.sol +21 -0
  123. package/scripts/interactions/InteractUpdateMbRecencyCheck.s.sol +27 -0
  124. package/scripts/interactions/InteractUpdateMediaChunkCount.s.sol +27 -0
  125. package/scripts/interactions/InteractUpdateMediaChunkSize.s.sol +27 -0
  126. package/scripts/interactions/helpers/AlphaHelper.sol +149 -0
  127. package/scripts/interactions/helpers/RiverConfigValues.sol +22 -0
  128. package/scripts/interactions/interfaces/IL1StandardBridge.sol +35 -0
  129. package/scripts/interactions/interfaces/IL2StandardBridge.sol +69 -0
  130. package/src/airdrop/drop/DropBase.sol +210 -0
  131. package/src/airdrop/drop/DropClaim.sol +55 -0
  132. package/src/airdrop/drop/DropFacet.sol +176 -0
  133. package/src/airdrop/drop/DropGroup.sol +111 -0
  134. package/src/airdrop/drop/DropStorage.sol +23 -0
  135. package/src/airdrop/drop/IDropFacet.sol +136 -0
  136. package/src/airdrop/points/CheckIn.sol +71 -0
  137. package/src/airdrop/points/ITownsPoints.sol +64 -0
  138. package/src/airdrop/points/TownsPoints.sol +196 -0
  139. package/src/airdrop/points/TownsPointsStorage.sol +22 -0
  140. package/src/apps/BaseApp.sol +62 -0
  141. package/src/apps/ITownsApp.sol +28 -0
  142. package/src/apps/SchemaResolver.sol +170 -0
  143. package/src/apps/facets/attest/AttestationBase.sol +335 -0
  144. package/src/apps/facets/attest/AttestationLib.sol +64 -0
  145. package/src/apps/facets/attest/AttestationRegistry.sol +39 -0
  146. package/src/apps/facets/attest/AttestationStorage.sol +35 -0
  147. package/src/apps/facets/attest/IAttestationRegistry.sol +43 -0
  148. package/src/apps/facets/registry/AppRegistryBase.sol +403 -0
  149. package/src/apps/facets/registry/AppRegistryFacet.sol +173 -0
  150. package/src/apps/facets/registry/AppRegistryStorage.sol +53 -0
  151. package/src/apps/facets/registry/IAppRegistry.sol +159 -0
  152. package/src/apps/facets/schema/ISchema.sol +14 -0
  153. package/src/apps/facets/schema/SchemaBase.sol +88 -0
  154. package/src/apps/facets/schema/SchemaLib.sol +14 -0
  155. package/src/apps/facets/schema/SchemaRegistry.sol +51 -0
  156. package/src/apps/facets/schema/SchemaStorage.sol +34 -0
  157. package/src/apps/helpers/ISimpleApp.sol +51 -0
  158. package/src/apps/helpers/SimpleApp.sol +97 -0
  159. package/src/apps/helpers/SimpleAppStorage.sol +27 -0
  160. package/src/base/registry/facets/checker/EntitlementChecker.sol +237 -0
  161. package/src/base/registry/facets/checker/EntitlementCheckerStorage.sol +28 -0
  162. package/src/base/registry/facets/checker/IEntitlementChecker.sol +95 -0
  163. package/src/base/registry/facets/delegation/ISpaceDelegation.sol +69 -0
  164. package/src/base/registry/facets/delegation/SpaceDelegationFacet.sol +250 -0
  165. package/src/base/registry/facets/delegation/SpaceDelegationStorage.sol +35 -0
  166. package/src/base/registry/facets/distribution/v1/IRewardsDistribution.sol +51 -0
  167. package/src/base/registry/facets/distribution/v1/RewardsDistribution.sol +439 -0
  168. package/src/base/registry/facets/distribution/v1/RewardsDistributionStorage.sol +32 -0
  169. package/src/base/registry/facets/distribution/v2/DelegationProxy.sol +53 -0
  170. package/src/base/registry/facets/distribution/v2/IRewardsDistribution.sol +372 -0
  171. package/src/base/registry/facets/distribution/v2/RewardsDistributionBase.sol +299 -0
  172. package/src/base/registry/facets/distribution/v2/RewardsDistributionStorage.sol +37 -0
  173. package/src/base/registry/facets/distribution/v2/RewardsDistributionV2.sol +392 -0
  174. package/src/base/registry/facets/distribution/v2/StakingRewards.sol +466 -0
  175. package/src/base/registry/facets/mainnet/ICrossDomainMessenger.sol +58 -0
  176. package/src/base/registry/facets/mainnet/IMainnetDelegation.sol +127 -0
  177. package/src/base/registry/facets/mainnet/MainnetDelegation.sol +119 -0
  178. package/src/base/registry/facets/mainnet/MainnetDelegationBase.sol +274 -0
  179. package/src/base/registry/facets/mainnet/MainnetDelegationStorage.sol +36 -0
  180. package/src/base/registry/facets/operator/INodeOperator.sol +91 -0
  181. package/src/base/registry/facets/operator/NodeOperatorFacet.sol +189 -0
  182. package/src/base/registry/facets/operator/NodeOperatorStorage.sol +39 -0
  183. package/src/base/registry/facets/xchain/IXChain.sol +54 -0
  184. package/src/base/registry/facets/xchain/XChain.sol +158 -0
  185. package/src/base/registry/facets/xchain/XChainCheckLib.sol +105 -0
  186. package/src/base/registry/facets/xchain/XChainLib.sol +46 -0
  187. package/src/diamond/facets/beacon/UpgradeableBeacon.sol +38 -0
  188. package/src/diamond/facets/beacon/UpgradeableBeaconFacet.sol +34 -0
  189. package/src/diamond/facets/governance/votes/Checkpoints.sol +642 -0
  190. package/src/diamond/facets/governance/votes/Votes.sol +63 -0
  191. package/src/diamond/facets/governance/votes/VotesBase.sol +274 -0
  192. package/src/diamond/facets/governance/votes/VotesStorage.sol +21 -0
  193. package/src/diamond/facets/governance/votes/enumerable/IVotesEnumerable.sol +38 -0
  194. package/src/diamond/facets/governance/votes/enumerable/VotesEnumerable.sol +39 -0
  195. package/src/diamond/facets/governance/votes/enumerable/VotesEnumerableLib.sol +102 -0
  196. package/src/diamond/facets/metadata/IMetadata.sol +27 -0
  197. package/src/diamond/facets/metadata/MetadataFacet.sol +71 -0
  198. package/src/diamond/facets/token/ERC5643/ERC5643.sol +51 -0
  199. package/src/diamond/facets/token/ERC5643/ERC5643Base.sol +48 -0
  200. package/src/diamond/facets/token/ERC5643/ERC5643Storage.sol +26 -0
  201. package/src/diamond/facets/token/ERC5643/IERC5643.sol +44 -0
  202. package/src/diamond/facets/token/ERC721A/ERC721A.sol +270 -0
  203. package/src/diamond/facets/token/ERC721A/ERC721ABase.sol +829 -0
  204. package/src/diamond/facets/token/ERC721A/ERC721ANonTransferable.sol +21 -0
  205. package/src/diamond/facets/token/ERC721A/ERC721AStorage.sol +115 -0
  206. package/src/diamond/facets/token/ERC721A/IERC721A.sol +283 -0
  207. package/src/diamond/facets/token/ERC721A/extensions/ERC721AQueryable.sol +134 -0
  208. package/src/diamond/facets/token/ERC721A/extensions/IERC721AQueryable.sol +83 -0
  209. package/src/diamond/utils/Context.sol +19 -0
  210. package/src/factory/SpaceFactoryInit.sol +17 -0
  211. package/src/factory/facets/architect/Architect.sol +98 -0
  212. package/src/factory/facets/architect/ArchitectBase.sol +95 -0
  213. package/src/factory/facets/architect/ArchitectStorage.sol +28 -0
  214. package/src/factory/facets/architect/IArchitect.sol +155 -0
  215. package/src/factory/facets/architect/ImplementationStorage.sol +42 -0
  216. package/src/factory/facets/architect/pricing/IPricingModules.sol +41 -0
  217. package/src/factory/facets/architect/pricing/PricingModulesBase.sol +89 -0
  218. package/src/factory/facets/architect/pricing/PricingModulesFacet.sol +40 -0
  219. package/src/factory/facets/architect/pricing/PricingModulesStorage.sol +30 -0
  220. package/src/factory/facets/create/CreateSpace.sol +107 -0
  221. package/src/factory/facets/create/CreateSpaceLib.sol +335 -0
  222. package/src/factory/facets/create/ICreateSpace.sol +70 -0
  223. package/src/factory/facets/feature/FeatureConditionLib.sol +53 -0
  224. package/src/factory/facets/feature/FeatureManagerFacet.sol +66 -0
  225. package/src/factory/facets/feature/FeatureManagerLib.sol +168 -0
  226. package/src/factory/facets/feature/IFeatureManagerFacet.sol +73 -0
  227. package/src/factory/facets/partner/IPartnerRegistry.sol +56 -0
  228. package/src/factory/facets/partner/PartnerRegistry.sol +57 -0
  229. package/src/factory/facets/partner/PartnerRegistryBase.sol +132 -0
  230. package/src/factory/facets/partner/PartnerRegistryStorage.sol +40 -0
  231. package/src/factory/facets/platform/requirements/IPlatformRequirements.sol +143 -0
  232. package/src/factory/facets/platform/requirements/PlatformRequirementsBase.sol +124 -0
  233. package/src/factory/facets/platform/requirements/PlatformRequirementsFacet.sol +122 -0
  234. package/src/factory/facets/platform/requirements/PlatformRequirementsStorage.sol +41 -0
  235. package/src/factory/facets/registry/IImplementationRegistry.sol +46 -0
  236. package/src/factory/facets/registry/ImplementationRegistry.sol +64 -0
  237. package/src/factory/facets/registry/ImplementationRegistryStorage.sol +28 -0
  238. package/src/factory/facets/wallet-link/IWalletLink.sol +218 -0
  239. package/src/factory/facets/wallet-link/WalletLink.sol +108 -0
  240. package/src/factory/facets/wallet-link/WalletLinkBase.sol +492 -0
  241. package/src/factory/facets/wallet-link/interfaces/IDelegateRegistry.sol +63 -0
  242. package/src/factory/facets/wallet-link/interfaces/IDelegateRegistryV1.sol +35 -0
  243. package/src/factory/facets/wallet-link/interfaces/ISCL_EIP6565.sol +24 -0
  244. package/src/factory/facets/wallet-link/libraries/SolanaUtils.sol +161 -0
  245. package/src/factory/facets/wallet-link/libraries/WalletLib.sol +62 -0
  246. package/src/river/registry/facets/config/IRiverConfig.sol +117 -0
  247. package/src/river/registry/facets/config/RiverConfig.sol +174 -0
  248. package/src/river/registry/facets/node/INodeRegistry.sol +69 -0
  249. package/src/river/registry/facets/node/NodeRegistry.sol +143 -0
  250. package/src/river/registry/facets/operator/IOperatorRegistry.sol +28 -0
  251. package/src/river/registry/facets/operator/OperatorRegistry.sol +86 -0
  252. package/src/river/registry/facets/stream/IStreamRegistry.sol +184 -0
  253. package/src/river/registry/facets/stream/StreamRegistry.sol +396 -0
  254. package/src/river/registry/libraries/RegistryErrors.sol +24 -0
  255. package/src/river/registry/libraries/RegistryStorage.sol +181 -0
  256. package/src/router/ISwapRouter.sol +226 -0
  257. package/src/router/Permit2Hash.sol +92 -0
  258. package/src/router/SwapRouter.sol +463 -0
  259. package/src/router/SwapRouterStorage.sol +21 -0
  260. package/src/spaces/entitlements/ICrossChainEntitlement.sol +22 -0
  261. package/src/spaces/entitlements/IEntitlement.sol +61 -0
  262. package/src/spaces/entitlements/PolymarketEntitlement.sol +79 -0
  263. package/src/spaces/entitlements/poap/IPOAP.sol +26 -0
  264. package/src/spaces/entitlements/poap/PoapEntitlement.sol +56 -0
  265. package/src/spaces/entitlements/rule/IRuleEntitlement.sol +174 -0
  266. package/src/spaces/entitlements/rule/RuleEntitlement.sol +183 -0
  267. package/src/spaces/entitlements/rule/RuleEntitlementV2.sol +219 -0
  268. package/src/spaces/entitlements/user/IUserEntitlement.sol +24 -0
  269. package/src/spaces/entitlements/user/UserEntitlement.sol +273 -0
  270. package/src/spaces/facets/DependencyLib.sol +60 -0
  271. package/src/spaces/facets/Entitled.sol +172 -0
  272. package/src/spaces/facets/Permissions.sol +21 -0
  273. package/src/spaces/facets/account/AppAccount.sol +93 -0
  274. package/src/spaces/facets/account/AppAccountBase.sol +275 -0
  275. package/src/spaces/facets/account/AppAccountStorage.sol +63 -0
  276. package/src/spaces/facets/account/IAppAccount.sol +71 -0
  277. package/src/spaces/facets/account/SignerFacet.sol +26 -0
  278. package/src/spaces/facets/banning/Banning.sol +41 -0
  279. package/src/spaces/facets/banning/BanningBase.sol +33 -0
  280. package/src/spaces/facets/banning/BanningStorage.sol +23 -0
  281. package/src/spaces/facets/banning/IBanning.sol +35 -0
  282. package/src/spaces/facets/channels/ChannelBase.sol +87 -0
  283. package/src/spaces/facets/channels/ChannelService.sol +177 -0
  284. package/src/spaces/facets/channels/ChannelStorage.sol +34 -0
  285. package/src/spaces/facets/channels/Channels.sol +80 -0
  286. package/src/spaces/facets/channels/IChannel.sol +98 -0
  287. package/src/spaces/facets/dispatcher/DispatcherBase.sol +86 -0
  288. package/src/spaces/facets/dispatcher/DispatcherStorage.sol +21 -0
  289. package/src/spaces/facets/dispatcher/IDispatcher.sol +6 -0
  290. package/src/spaces/facets/entitlements/EntitlementsManager.sol +49 -0
  291. package/src/spaces/facets/entitlements/EntitlementsManagerBase.sol +87 -0
  292. package/src/spaces/facets/entitlements/EntitlementsManagerService.sol +142 -0
  293. package/src/spaces/facets/entitlements/EntitlementsManagerStorage.sol +34 -0
  294. package/src/spaces/facets/entitlements/IEntitlementsManager.sol +67 -0
  295. package/src/spaces/facets/entitlements/extensions/EntitlementDataQueryable.sol +153 -0
  296. package/src/spaces/facets/entitlements/extensions/IEntitlementDataQueryable.sol +32 -0
  297. package/src/spaces/facets/executor/ExecutorBase.sol +564 -0
  298. package/src/spaces/facets/executor/ExecutorFacet.sol +178 -0
  299. package/src/spaces/facets/executor/ExecutorStorage.sol +99 -0
  300. package/src/spaces/facets/executor/GroupLib.sol +128 -0
  301. package/src/spaces/facets/executor/IExecutor.sol +287 -0
  302. package/src/spaces/facets/executor/hooks/HookBase.sol +172 -0
  303. package/src/spaces/facets/executor/hooks/HookLib.sol +38 -0
  304. package/src/spaces/facets/executor/hooks/IHookBase.sol +48 -0
  305. package/src/spaces/facets/gated/EntitlementGated.sol +59 -0
  306. package/src/spaces/facets/gated/EntitlementGatedBase.sol +324 -0
  307. package/src/spaces/facets/gated/EntitlementGatedStorage.sol +29 -0
  308. package/src/spaces/facets/gated/IEntitlementGated.sol +55 -0
  309. package/src/spaces/facets/guardian/GuardianBase.sol +80 -0
  310. package/src/spaces/facets/guardian/GuardianFacet.sol +43 -0
  311. package/src/spaces/facets/guardian/GuardianStorage.sol +27 -0
  312. package/src/spaces/facets/guardian/IGuardian.sol +54 -0
  313. package/src/spaces/facets/membership/IMembership.sol +216 -0
  314. package/src/spaces/facets/membership/MembershipBase.sol +272 -0
  315. package/src/spaces/facets/membership/MembershipFacet.sol +191 -0
  316. package/src/spaces/facets/membership/MembershipStorage.sol +40 -0
  317. package/src/spaces/facets/membership/join/MembershipJoin.sol +547 -0
  318. package/src/spaces/facets/membership/metadata/IMembershipMetadata.sol +9 -0
  319. package/src/spaces/facets/membership/metadata/MembershipMetadata.sol +32 -0
  320. package/src/spaces/facets/membership/pricing/IMembershipPricing.sol +18 -0
  321. package/src/spaces/facets/membership/pricing/fixed/FixedPricing.sol +29 -0
  322. package/src/spaces/facets/membership/pricing/fixed/FixedPricingStorage.sol +27 -0
  323. package/src/spaces/facets/membership/pricing/tiered/TieredLogPricingOracleV2.sol +148 -0
  324. package/src/spaces/facets/membership/pricing/tiered/TieredLogPricingOracleV3.sol +137 -0
  325. package/src/spaces/facets/membership/token/MembershipToken.sol +25 -0
  326. package/src/spaces/facets/owner/ISpaceOwner.sol +85 -0
  327. package/src/spaces/facets/owner/SpaceOwner.sol +174 -0
  328. package/src/spaces/facets/owner/SpaceOwnerBase.sol +121 -0
  329. package/src/spaces/facets/owner/SpaceOwnerStorage.sol +41 -0
  330. package/src/spaces/facets/owner/SpaceOwnerUriBase.sol +54 -0
  331. package/src/spaces/facets/points/PointsBase.sol +35 -0
  332. package/src/spaces/facets/prepay/IPrepay.sol +43 -0
  333. package/src/spaces/facets/prepay/PrepayBase.sol +27 -0
  334. package/src/spaces/facets/prepay/PrepayFacet.sol +59 -0
  335. package/src/spaces/facets/prepay/PrepayStorage.sol +26 -0
  336. package/src/spaces/facets/proxy/ISpaceProxyInitializer.sol +21 -0
  337. package/src/spaces/facets/proxy/SpaceProxy.sol +15 -0
  338. package/src/spaces/facets/proxy/SpaceProxyInitializer.sol +55 -0
  339. package/src/spaces/facets/referrals/IReferrals.sol +98 -0
  340. package/src/spaces/facets/referrals/ReferralsBase.sol +81 -0
  341. package/src/spaces/facets/referrals/ReferralsFacet.sol +65 -0
  342. package/src/spaces/facets/referrals/ReferralsStorage.sol +36 -0
  343. package/src/spaces/facets/review/IReview.sol +50 -0
  344. package/src/spaces/facets/review/ReviewFacet.sol +105 -0
  345. package/src/spaces/facets/review/ReviewStorage.sol +29 -0
  346. package/src/spaces/facets/roles/IRoles.sol +197 -0
  347. package/src/spaces/facets/roles/Roles.sol +123 -0
  348. package/src/spaces/facets/roles/RolesBase.sol +420 -0
  349. package/src/spaces/facets/roles/RolesStorage.sol +132 -0
  350. package/src/spaces/facets/swap/ISwapFacet.sol +91 -0
  351. package/src/spaces/facets/swap/SwapFacet.sol +290 -0
  352. package/src/spaces/facets/swap/SwapFacetStorage.sol +24 -0
  353. package/src/spaces/facets/tipping/ITipping.sol +80 -0
  354. package/src/spaces/facets/tipping/TippingBase.sol +73 -0
  355. package/src/spaces/facets/tipping/TippingFacet.sol +123 -0
  356. package/src/spaces/facets/treasury/ITreasury.sol +64 -0
  357. package/src/spaces/facets/treasury/Treasury.sol +82 -0
  358. package/src/spaces/facets/xchain/SpaceEntitlementGated.sol +62 -0
  359. package/src/tokens/Member.sol +246 -0
  360. package/src/tokens/lock/ILock.sol +42 -0
  361. package/src/tokens/lock/LockBase.sol +64 -0
  362. package/src/tokens/lock/LockFacet.sol +44 -0
  363. package/src/tokens/lock/LockStorage.sol +26 -0
  364. package/src/tokens/mainnet/claimer/AuthorizedClaimerStorage.sol +26 -0
  365. package/src/tokens/mainnet/claimer/AuthorizedClaimers.sol +84 -0
  366. package/src/tokens/mainnet/claimer/IAuthorizedClaimers.sol +36 -0
  367. package/src/tokens/mainnet/delegation/ProxyBatchDelegation.sol +86 -0
  368. package/src/tokens/migration/ITokenMigration.sol +35 -0
  369. package/src/tokens/migration/TokenMigrationFacet.sol +86 -0
  370. package/src/tokens/migration/TokenMigrationStorage.sol +27 -0
  371. package/src/tokens/towns/base/IERC7802.sol +30 -0
  372. package/src/tokens/towns/base/IOptimismMintableERC20.sol +31 -0
  373. package/src/tokens/towns/base/ISemver.sol +13 -0
  374. package/src/tokens/towns/base/Towns.sol +283 -0
  375. package/src/tokens/towns/base/TownsDeployer.sol +32 -0
  376. package/src/tokens/towns/base/TownsLib.sol +31 -0
  377. package/src/tokens/towns/base/versions/TownsV2.sol +15 -0
  378. package/src/tokens/towns/mainnet/ITowns.sol +56 -0
  379. package/src/tokens/towns/mainnet/Towns.sol +220 -0
  380. package/src/tokens/towns/mainnet/libs/TokenInflationLib.sol +89 -0
  381. package/src/tokens/towns/multichain/Towns.sol +19 -0
  382. package/src/tokens/towns/multichain/wTowns.sol +18 -0
  383. package/src/utils/Airdrop.sol +156 -0
  384. package/src/utils/airdrop/merkle/IMerkleAirdrop.sol +55 -0
  385. package/src/utils/airdrop/merkle/MerkleAirdrop.sol +118 -0
  386. package/src/utils/airdrop/merkle/MerkleAirdropStorage.sol +29 -0
  387. package/src/utils/interfaces/AggregatorV3Interface.sol +37 -0
  388. package/src/utils/interfaces/IMulticall.sol +10 -0
  389. package/src/utils/interfaces/IWETH.sol +10 -0
  390. package/src/utils/libraries/BasisPoints.sol +24 -0
  391. package/src/utils/libraries/Create2Utils.sol +74 -0
  392. package/src/utils/libraries/CurrencyTransfer.sol +99 -0
  393. package/src/utils/libraries/CustomRevert.sol +49 -0
  394. package/src/utils/libraries/Factory.sol +66 -0
  395. package/src/utils/libraries/StringSet.sol +190 -0
  396. package/src/utils/libraries/Validator.sol +31 -0
@@ -0,0 +1,237 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IEntitlementChecker} from "./IEntitlementChecker.sol";
6
+ import {IEntitlementGatedBase} from "src/spaces/facets/gated/IEntitlementGated.sol";
7
+
8
+ // libraries
9
+
10
+ import {EntitlementCheckerStorage} from "./EntitlementCheckerStorage.sol";
11
+ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
12
+ import {NodeOperatorStatus, NodeOperatorStorage} from "src/base/registry/facets/operator/NodeOperatorStorage.sol";
13
+ import {XChainLib} from "src/base/registry/facets/xchain/XChainLib.sol";
14
+ import {CustomRevert} from "src/utils/libraries/CustomRevert.sol";
15
+
16
+ // contracts
17
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
18
+
19
+ contract EntitlementChecker is IEntitlementChecker, Facet {
20
+ using EnumerableSet for EnumerableSet.AddressSet;
21
+ using EnumerableSet for EnumerableSet.UintSet;
22
+ using EnumerableSet for EnumerableSet.Bytes32Set;
23
+ using CustomRevert for bytes4;
24
+
25
+ // =============================================================
26
+ // Initializer
27
+ // =============================================================
28
+
29
+ function __EntitlementChecker_init() external onlyInitializing {
30
+ _addInterface(type(IEntitlementChecker).interfaceId);
31
+ }
32
+
33
+ // =============================================================
34
+ // Modifiers
35
+ // =============================================================
36
+ modifier onlyNodeOperator(address node, address operator) {
37
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
38
+
39
+ if (layout.operatorByNode[node] != operator) {
40
+ EntitlementChecker_InvalidNodeOperator.selector.revertWith();
41
+ }
42
+ _;
43
+ }
44
+
45
+ modifier onlyRegisteredApprovedOperator() {
46
+ NodeOperatorStorage.Layout storage nodeOperatorLayout = NodeOperatorStorage.layout();
47
+
48
+ if (!nodeOperatorLayout.operators.contains(msg.sender)) {
49
+ EntitlementChecker_InvalidOperator.selector.revertWith();
50
+ }
51
+ _;
52
+
53
+ if (nodeOperatorLayout.statusByOperator[msg.sender] != NodeOperatorStatus.Approved) {
54
+ EntitlementChecker_OperatorNotActive.selector.revertWith();
55
+ }
56
+ }
57
+
58
+ // =============================================================
59
+ // External
60
+ // =============================================================
61
+
62
+ /// @inheritdoc IEntitlementChecker
63
+ function registerNode(address node) external onlyRegisteredApprovedOperator {
64
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
65
+
66
+ if (layout.nodes.contains(node)) {
67
+ EntitlementChecker_NodeAlreadyRegistered.selector.revertWith();
68
+ }
69
+
70
+ layout.nodes.add(node);
71
+ layout.operatorByNode[node] = msg.sender;
72
+
73
+ emit NodeRegistered(node);
74
+ }
75
+
76
+ /// @inheritdoc IEntitlementChecker
77
+ function unregisterNode(address node) external onlyNodeOperator(node, msg.sender) {
78
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
79
+
80
+ if (!layout.nodes.contains(node)) {
81
+ EntitlementChecker_NodeNotRegistered.selector.revertWith();
82
+ }
83
+
84
+ layout.nodes.remove(node);
85
+ delete layout.operatorByNode[node];
86
+
87
+ emit NodeUnregistered(node);
88
+ }
89
+
90
+ /// @inheritdoc IEntitlementChecker
91
+ function isValidNode(address node) external view returns (bool) {
92
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
93
+ return layout.nodes.contains(node);
94
+ }
95
+
96
+ /// @inheritdoc IEntitlementChecker
97
+ function getNodeCount() external view returns (uint256) {
98
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
99
+ return layout.nodes.length();
100
+ }
101
+
102
+ /// @inheritdoc IEntitlementChecker
103
+ function getNodeAtIndex(uint256 index) external view returns (address) {
104
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
105
+
106
+ require(index < layout.nodes.length(), "Index out of bounds");
107
+ return layout.nodes.at(index);
108
+ }
109
+
110
+ /// @inheritdoc IEntitlementChecker
111
+ function getRandomNodes(uint256 count) external view returns (address[] memory) {
112
+ return _getRandomNodes(count);
113
+ }
114
+
115
+ /// @inheritdoc IEntitlementChecker
116
+ function requestEntitlementCheck(
117
+ address walletAddress,
118
+ bytes32 transactionId,
119
+ uint256 roleId,
120
+ address[] memory nodes
121
+ ) external {
122
+ emit EntitlementCheckRequested(walletAddress, msg.sender, transactionId, roleId, nodes);
123
+ }
124
+
125
+ /// @inheritdoc IEntitlementChecker
126
+ function requestEntitlementCheckV2(
127
+ address walletAddress,
128
+ bytes32 transactionId,
129
+ uint256 requestId,
130
+ bytes memory extraData
131
+ ) external payable {
132
+ address space = msg.sender;
133
+ address senderAddress = abi.decode(extraData, (address));
134
+
135
+ XChainLib.Layout storage layout = XChainLib.layout();
136
+
137
+ layout.requestsBySender[senderAddress].add(transactionId);
138
+
139
+ // Only create the request if it doesn't exist yet
140
+ XChainLib.Request storage request = layout.requests[transactionId];
141
+ if (request.caller == address(0)) {
142
+ // First time creating this request
143
+ layout.requests[transactionId] = XChainLib.Request({
144
+ caller: space,
145
+ blockNumber: block.number,
146
+ value: msg.value,
147
+ completed: false,
148
+ receiver: walletAddress
149
+ });
150
+ } else {
151
+ if (msg.value != 0) {
152
+ EntitlementChecker_InvalidValue.selector.revertWith();
153
+ }
154
+ }
155
+
156
+ address[] memory randomNodes = _getRandomNodes(5);
157
+
158
+ XChainLib.Check storage check = XChainLib.layout().checks[transactionId];
159
+
160
+ check.requestIds.add(requestId);
161
+
162
+ for (uint256 i; i < randomNodes.length; ++i) {
163
+ check.nodes[requestId].add(randomNodes[i]);
164
+ check.votes[requestId].push(
165
+ IEntitlementGatedBase.NodeVote({
166
+ node: randomNodes[i],
167
+ vote: IEntitlementGatedBase.NodeVoteStatus.NOT_VOTED
168
+ })
169
+ );
170
+ }
171
+
172
+ emit EntitlementCheckRequestedV2(
173
+ walletAddress,
174
+ space,
175
+ address(this),
176
+ transactionId,
177
+ requestId,
178
+ randomNodes
179
+ );
180
+ }
181
+
182
+ /// @inheritdoc IEntitlementChecker
183
+ function getNodesByOperator(address operator) external view returns (address[] memory nodes) {
184
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
185
+ uint256 totalNodeCount = layout.nodes.length();
186
+ nodes = new address[](totalNodeCount);
187
+ uint256 nodeCount;
188
+ for (uint256 i; i < totalNodeCount; ++i) {
189
+ address node = layout.nodes.at(i);
190
+ if (layout.operatorByNode[node] == operator) {
191
+ unchecked {
192
+ nodes[nodeCount++] = node;
193
+ }
194
+ }
195
+ }
196
+ assembly ("memory-safe") {
197
+ mstore(nodes, nodeCount) // Update the length of the array
198
+ }
199
+ }
200
+
201
+ // =============================================================
202
+ // Internal
203
+ // =============================================================
204
+ function _getRandomNodes(uint256 count) internal view returns (address[] memory randomNodes) {
205
+ EntitlementCheckerStorage.Layout storage layout = EntitlementCheckerStorage.layout();
206
+
207
+ uint256 nodeCount = layout.nodes.length();
208
+
209
+ if (count > nodeCount) {
210
+ EntitlementChecker_InsufficientNumberOfNodes.selector.revertWith();
211
+ }
212
+
213
+ randomNodes = new address[](count);
214
+ uint256[] memory indices = new uint256[](nodeCount);
215
+
216
+ for (uint256 i; i < nodeCount; ++i) {
217
+ indices[i] = i;
218
+ }
219
+
220
+ unchecked {
221
+ for (uint256 i; i < count; ++i) {
222
+ // Adjust random function to generate within range 0 to n-1
223
+ uint256 rand = _pseudoRandom(i, nodeCount);
224
+ randomNodes[i] = layout.nodes.at(indices[rand]);
225
+ // Move the last element to the used slot and reduce the pool size
226
+ indices[rand] = indices[--nodeCount];
227
+ }
228
+ }
229
+ }
230
+
231
+ // Generate a pseudo-random index based on a seed and the node count
232
+ function _pseudoRandom(uint256 seed, uint256 nodeCount) internal view returns (uint256) {
233
+ return
234
+ uint256(keccak256(abi.encode(block.prevrandao, block.timestamp, seed, msg.sender))) %
235
+ nodeCount;
236
+ }
237
+ }
@@ -0,0 +1,28 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
8
+
9
+ // contracts
10
+
11
+ library EntitlementCheckerStorage {
12
+ // keccak256(abi.encode(uint256(keccak256("facets.entitlement.checker.storage")) - 1)) &
13
+ // ~bytes32(uint256(0xff))
14
+ bytes32 internal constant STORAGE_SLOT =
15
+ 0x180c1d0b9e5eeea9f2f078bc2712cd77acc6afea03b37705abe96dda6f602600;
16
+
17
+ struct Layout {
18
+ EnumerableSet.AddressSet nodes;
19
+ mapping(address node => address operator) operatorByNode;
20
+ }
21
+
22
+ function layout() internal pure returns (Layout storage l) {
23
+ bytes32 slot = STORAGE_SLOT;
24
+ assembly {
25
+ l.slot := slot
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,95 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ interface IEntitlementCheckerBase {
5
+ error EntitlementChecker_NodeAlreadyRegistered();
6
+ error EntitlementChecker_NodeNotRegistered();
7
+ error EntitlementChecker_InsufficientNumberOfNodes();
8
+ error EntitlementChecker_InvalidNodeOperator();
9
+ error EntitlementChecker_InvalidOperator();
10
+ error EntitlementChecker_OperatorNotActive();
11
+ error EntitlementChecker_NoPendingRequests();
12
+ error EntitlementChecker_InsufficientFunds();
13
+ error EntitlementChecker_NoRefundsAvailable();
14
+ error EntitlementChecker_InvalidValue();
15
+
16
+ // Events
17
+ event NodeRegistered(address indexed nodeAddress);
18
+ event NodeUnregistered(address indexed nodeAddress);
19
+
20
+ /// @notice Event emitted when an entitlement check is requested
21
+ event EntitlementCheckRequested(
22
+ address callerAddress,
23
+ address contractAddress,
24
+ bytes32 transactionId,
25
+ uint256 roleId,
26
+ address[] selectedNodes
27
+ );
28
+
29
+ event EntitlementCheckRequestedV2(
30
+ address walletAddress,
31
+ address spaceAddress,
32
+ address resolverAddress,
33
+ bytes32 transactionId,
34
+ uint256 roleId,
35
+ address[] selectedNodes
36
+ );
37
+ }
38
+
39
+ interface IEntitlementChecker is IEntitlementCheckerBase {
40
+ /// @notice Register a new node in the system
41
+ /// @param node The address of the node to register
42
+ function registerNode(address node) external;
43
+
44
+ /// @notice Unregister an existing node from the system
45
+ /// @param node The address of the node to unregister
46
+ function unregisterNode(address node) external;
47
+
48
+ /// @notice Check if a node address is registered and valid
49
+ /// @param node The address of the node to check
50
+ /// @return bool True if the node is valid, false otherwise
51
+ function isValidNode(address node) external view returns (bool);
52
+
53
+ /// @notice Get the total number of registered nodes
54
+ /// @return uint256 The count of registered nodes
55
+ function getNodeCount() external view returns (uint256);
56
+
57
+ /// @notice Get the node address at a specific index
58
+ /// @param index The index of the node to retrieve
59
+ /// @return address The address of the node at the given index
60
+ function getNodeAtIndex(uint256 index) external view returns (address);
61
+
62
+ /// @notice Get a random selection of registered nodes
63
+ /// @param count The number of random nodes to return
64
+ /// @return address[] Array of randomly selected node addresses
65
+ function getRandomNodes(uint256 count) external view returns (address[] memory);
66
+
67
+ /// @notice Request an entitlement check for a transaction
68
+ /// @param callerAddress The address initiating the check
69
+ /// @param transactionId The unique identifier of the transaction
70
+ /// @param roleId The role ID to check entitlements against
71
+ /// @param nodes Array of node addresses that will perform the check
72
+ function requestEntitlementCheck(
73
+ address callerAddress,
74
+ bytes32 transactionId,
75
+ uint256 roleId,
76
+ address[] memory nodes
77
+ ) external;
78
+
79
+ /// @notice Request an entitlement check with additional data (V2)
80
+ /// @param walletAddress The wallet address to check entitlements for
81
+ /// @param transactionId The unique identifier of the transaction
82
+ /// @param requestId The unique identifier for this specific request
83
+ /// @param extraData Additional data required for the check
84
+ function requestEntitlementCheckV2(
85
+ address walletAddress,
86
+ bytes32 transactionId,
87
+ uint256 requestId,
88
+ bytes memory extraData
89
+ ) external payable;
90
+
91
+ /// @notice Get all nodes registered to a specific operator
92
+ /// @param operator The address of the operator
93
+ /// @return address[] Array of node addresses registered to the operator
94
+ function getNodesByOperator(address operator) external view returns (address[] memory);
95
+ }
@@ -0,0 +1,69 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ interface ISpaceDelegationBase {
5
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
6
+ /* ERRORS */
7
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
8
+
9
+ error SpaceDelegation__InvalidAddress();
10
+ error SpaceDelegation__InvalidOperator();
11
+ error SpaceDelegation__InvalidSpace();
12
+ error SpaceDelegation__NotSpaceOwner();
13
+ error SpaceDelegation__NotSpaceMember();
14
+ error SpaceDelegation__AlreadyDelegated(address operator);
15
+ error SpaceDelegation__NotDelegated();
16
+ error SpaceDelegation__InvalidStakeRequirement();
17
+
18
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
19
+ /* EVENTS */
20
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
21
+
22
+ event SpaceDelegatedToOperator(address indexed space, address indexed operator);
23
+ event RiverTokenChanged(address indexed riverToken);
24
+ event SpaceFactoryChanged(address indexed spaceFactory);
25
+ }
26
+
27
+ interface ISpaceDelegation is ISpaceDelegationBase {
28
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
29
+ /* DELEGATION */
30
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
31
+
32
+ /// @notice Adds a space delegation to an operator
33
+ /// @param space The address of the space
34
+ /// @param operator The address of the operator
35
+ function addSpaceDelegation(address space, address operator) external;
36
+
37
+ /// @notice Removes a space delegation from an operator
38
+ /// @param space The address of the space
39
+ function removeSpaceDelegation(address space) external;
40
+
41
+ /// @notice Gets the operator address for a given space
42
+ /// @param space The address of the space
43
+ /// @return The address of the operator delegated to the space
44
+ function getSpaceDelegation(address space) external view returns (address);
45
+
46
+ /// @notice Gets all spaces delegated to a specific operator
47
+ /// @param operator The address of the operator
48
+ /// @return An array of space addresses delegated to the operator
49
+ function getSpaceDelegationsByOperator(
50
+ address operator
51
+ ) external view returns (address[] memory);
52
+
53
+ /// @notice Gets the total delegation for a specific operator
54
+ /// @param operator The address of the operator
55
+ /// @return The total amount delegated to the operator
56
+ function getTotalDelegation(address operator) external view returns (uint256);
57
+
58
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
59
+ /* FACTORY */
60
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
61
+
62
+ /// @notice Sets the address of the space factory
63
+ /// @param spaceFactory The address of the space factory
64
+ function setSpaceFactory(address spaceFactory) external;
65
+
66
+ /// @notice Gets the address of the space factory
67
+ /// @return The address of the space factory
68
+ function getSpaceFactory() external view returns (address);
69
+ }
@@ -0,0 +1,250 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
6
+ import {IERC173} from "@towns-protocol/diamond/src/facets/ownable/IERC173.sol";
7
+ import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
8
+ import {IArchitect} from "../../../../factory/facets/architect/IArchitect.sol";
9
+ import {IVotesEnumerable} from "../../../../diamond/facets/governance/votes/enumerable/IVotesEnumerable.sol";
10
+ import {IMainnetDelegation} from "../mainnet/IMainnetDelegation.sol";
11
+ import {IRewardsDistributionBase} from "../distribution/v2/IRewardsDistribution.sol";
12
+ import {ISpaceDelegation} from "./ISpaceDelegation.sol";
13
+
14
+ // libraries
15
+ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
16
+ import {CustomRevert} from "../../../../utils/libraries/CustomRevert.sol";
17
+ import {NodeOperatorStatus, NodeOperatorStorage} from "../operator/NodeOperatorStorage.sol";
18
+ import {RewardsDistributionStorage} from "../distribution/v2/RewardsDistributionStorage.sol";
19
+ import {StakingRewards} from "../distribution/v2/StakingRewards.sol";
20
+ import {SpaceDelegationStorage} from "./SpaceDelegationStorage.sol";
21
+
22
+ // contracts
23
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
24
+ import {OwnableBase} from "@towns-protocol/diamond/src/facets/ownable/OwnableBase.sol";
25
+
26
+ contract SpaceDelegationFacet is ISpaceDelegation, OwnableBase, Facet {
27
+ using EnumerableSet for EnumerableSet.AddressSet;
28
+ using StakingRewards for StakingRewards.Layout;
29
+ using CustomRevert for bytes4;
30
+
31
+ modifier onlySpaceOwner(address space) {
32
+ if (!_isValidSpace(space)) SpaceDelegation__InvalidSpace.selector.revertWith();
33
+ if (!_isValidSpaceOwner(space)) SpaceDelegation__NotSpaceOwner.selector.revertWith();
34
+ _;
35
+ }
36
+
37
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
38
+ /* DELEGATION */
39
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
40
+
41
+ /**
42
+ * @inheritdoc ISpaceDelegation
43
+ * @dev Delegates a space to a node operator for reward distribution.
44
+ * Authorization logic:
45
+ * - Only space members can delegate a space that has never been delegated
46
+ * - Only the space owner can delegate/redelegate once the space has been delegated before
47
+ *
48
+ * Process:
49
+ * 1. Validates operator address and space existence
50
+ * 2. Checks operator is registered and not exiting
51
+ * 3. Validates caller is member (for never delegated) or owner (for previously delegated)
52
+ * 4. Sweeps any pending rewards from previous delegation
53
+ * 5. Updates storage mappings and delegation timestamp
54
+ * 6. Emits SpaceDelegatedToOperator event
55
+ */
56
+ function addSpaceDelegation(address space, address operator) external {
57
+ if (operator == address(0)) SpaceDelegation__InvalidAddress.selector.revertWith();
58
+
59
+ // validate that the space exists
60
+ if (!_isValidSpace(space)) SpaceDelegation__InvalidSpace.selector.revertWith();
61
+
62
+ SpaceDelegationStorage.Layout storage ds = SpaceDelegationStorage.layout();
63
+
64
+ address currentOperator = ds.operatorBySpace[space];
65
+
66
+ if (currentOperator == operator) SpaceDelegation__AlreadyDelegated.selector.revertWith();
67
+
68
+ // Authorization logic: only members can delegate if space has never been delegated,
69
+ // only owner can delegate/redelegate if space has been delegated before (even if removed)
70
+ if (ds.spaceDelegationTime[space] != 0) {
71
+ // space has been delegated before (even if currently removed), only owner can delegate
72
+ if (!_isValidSpaceOwner(space)) SpaceDelegation__NotSpaceOwner.selector.revertWith();
73
+ } else {
74
+ // Space has never been delegated, only members can delegate
75
+ if (!_isValidSpaceMember(space)) SpaceDelegation__NotSpaceMember.selector.revertWith();
76
+ }
77
+
78
+ NodeOperatorStorage.Layout storage nodeOperatorDs = NodeOperatorStorage.layout();
79
+
80
+ // check if the operator is valid
81
+ if (!nodeOperatorDs.operators.contains(operator))
82
+ SpaceDelegation__InvalidOperator.selector.revertWith();
83
+
84
+ // check if operator is not exiting
85
+ if (nodeOperatorDs.statusByOperator[operator] == NodeOperatorStatus.Exiting)
86
+ SpaceDelegation__InvalidOperator.selector.revertWith();
87
+
88
+ _sweepSpaceRewardsIfNecessary(space, currentOperator);
89
+
90
+ // remove the space from the current operator
91
+ ds.spacesByOperator[currentOperator].remove(space);
92
+
93
+ // overwrite the operator for this space
94
+ ds.operatorBySpace[space] = operator;
95
+
96
+ // add the space to this new operator array
97
+ ds.spacesByOperator[operator].add(space);
98
+ ds.spaceDelegationTime[space] = block.timestamp;
99
+
100
+ emit SpaceDelegatedToOperator(space, operator);
101
+ }
102
+
103
+ /**
104
+ * @inheritdoc ISpaceDelegation
105
+ * @dev Removes delegation from a space, returning it to an undelegated state.
106
+ * Only the space owner can call this function.
107
+ * Note: The delegation timestamp is preserved to maintain history that the space
108
+ * was delegated before, ensuring only the owner can redelegate.
109
+ *
110
+ * Process:
111
+ * 1. Validates space address and delegation existence
112
+ * 2. Sweeps any pending rewards to the current operator
113
+ * 3. Clears operator mappings but preserves delegation timestamp
114
+ * 4. Emits SpaceDelegatedToOperator event with address(0)
115
+ */
116
+ function removeSpaceDelegation(address space) external onlySpaceOwner(space) {
117
+ if (space == address(0)) SpaceDelegation__InvalidAddress.selector.revertWith();
118
+
119
+ SpaceDelegationStorage.Layout storage ds = SpaceDelegationStorage.layout();
120
+
121
+ address operator = ds.operatorBySpace[space];
122
+
123
+ if (operator == address(0)) SpaceDelegation__NotDelegated.selector.revertWith();
124
+
125
+ _sweepSpaceRewardsIfNecessary(space, operator);
126
+
127
+ ds.operatorBySpace[space] = address(0);
128
+ ds.spacesByOperator[operator].remove(space);
129
+ // don't reset spaceDelegationTime to preserve delegation history
130
+
131
+ emit SpaceDelegatedToOperator(space, address(0));
132
+ }
133
+
134
+ /// @inheritdoc ISpaceDelegation
135
+ function getSpaceDelegation(address space) external view returns (address) {
136
+ return SpaceDelegationStorage.layout().operatorBySpace[space];
137
+ }
138
+
139
+ /// @inheritdoc ISpaceDelegation
140
+ function getSpaceDelegationsByOperator(
141
+ address operator
142
+ ) external view returns (address[] memory) {
143
+ return SpaceDelegationStorage.layout().spacesByOperator[operator].values();
144
+ }
145
+
146
+ /// @inheritdoc ISpaceDelegation
147
+ function getTotalDelegation(address operator) external view returns (uint256) {
148
+ return _getTotalDelegation(operator);
149
+ }
150
+
151
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
152
+ /* FACTORY */
153
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
154
+
155
+ /// @inheritdoc ISpaceDelegation
156
+ function setSpaceFactory(address spaceFactory) external onlyOwner {
157
+ if (spaceFactory == address(0)) SpaceDelegation__InvalidAddress.selector.revertWith();
158
+
159
+ SpaceDelegationStorage.layout().spaceFactory = spaceFactory;
160
+ emit SpaceFactoryChanged(spaceFactory);
161
+ }
162
+
163
+ /// @inheritdoc ISpaceDelegation
164
+ function getSpaceFactory() public view returns (address) {
165
+ return SpaceDelegationStorage.layout().spaceFactory;
166
+ }
167
+
168
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
169
+ /* INTERNAL */
170
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
171
+
172
+ /// @dev Sweeps the rewards in the space delegation to the operator if necessary
173
+ /// @dev Handles two scenarios:
174
+ /// 1. If currentOperator exists: transfers accumulated rewards to the current operator
175
+ /// (rewards earned while the space was delegated to them)
176
+ /// 2. If no currentOperator: forfeits accumulated rewards (clears unallocated rewards from
177
+ /// existing stakes after undelegation that shouldn't go to a new operator)
178
+ /// @param space The space address to sweep rewards from
179
+ /// @param currentOperator The current operator (address(0) if undelegated)
180
+ function _sweepSpaceRewardsIfNecessary(address space, address currentOperator) internal {
181
+ StakingRewards.Layout storage staking = RewardsDistributionStorage.layout().staking;
182
+
183
+ uint256 reward;
184
+ if (currentOperator != address(0)) {
185
+ // transfer rewards from space to current operator
186
+ reward = staking.transferReward(space, currentOperator);
187
+ } else {
188
+ // forfeit rewards (clear without transfer)
189
+ reward = staking.sweepReward(space);
190
+ }
191
+
192
+ if (reward != 0) {
193
+ emit IRewardsDistributionBase.SpaceRewardsSwept(space, currentOperator, reward);
194
+ }
195
+ }
196
+
197
+ function _getTotalDelegation(address operator) internal view returns (uint256) {
198
+ SpaceDelegationStorage.Layout storage ds = SpaceDelegationStorage.layout();
199
+ (address riverToken_, address mainnetDelegation_) = (ds.riverToken, ds.mainnetDelegation);
200
+ if (riverToken_ == address(0) || mainnetDelegation_ == address(0)) return 0;
201
+
202
+ // get the delegation from the mainnet delegation
203
+ uint256 delegation = IMainnetDelegation(mainnetDelegation_).getDelegatedStakeByOperator(
204
+ operator
205
+ );
206
+
207
+ // get the delegation from the base delegation
208
+ address[] memory baseDelegators = IVotesEnumerable(riverToken_).getDelegatorsByDelegatee(
209
+ operator
210
+ );
211
+ for (uint256 i; i < baseDelegators.length; ++i) {
212
+ delegation += IERC20(riverToken_).balanceOf(baseDelegators[i]);
213
+ }
214
+
215
+ address[] memory spaces = ds.spacesByOperator[operator].values();
216
+
217
+ for (uint256 i; i < spaces.length; ++i) {
218
+ address[] memory usersDelegatingToSpace = IVotesEnumerable(riverToken_)
219
+ .getDelegatorsByDelegatee(spaces[i]);
220
+
221
+ for (uint256 j; j < usersDelegatingToSpace.length; ++j) {
222
+ delegation += IERC20(riverToken_).balanceOf(usersDelegatingToSpace[j]);
223
+ }
224
+ }
225
+
226
+ return delegation;
227
+ }
228
+
229
+ /// @dev Checks if the space is valid by verifying if it has a nonzero token ID in the factory
230
+ function _isValidSpace(address space) internal view returns (bool) {
231
+ return IArchitect(getSpaceFactory()).getTokenIdBySpace(space) != 0;
232
+ }
233
+
234
+ /// @dev Checks if the caller is the owner of the space
235
+ /// @dev Assumes that the space is valid
236
+ function _isValidSpaceOwner(address space) internal view returns (bool) {
237
+ return IERC173(space).owner() == msg.sender;
238
+ }
239
+
240
+ /// @dev Checks if the caller is a member of the space (has at least one membership token)
241
+ /// @dev Also considers the space owner as a member
242
+ /// @dev Assumes that the space is valid
243
+ function _isValidSpaceMember(address space) internal view returns (bool) {
244
+ // Check if caller is the space owner
245
+ if (IERC173(space).owner() == msg.sender) return true;
246
+
247
+ // Check if caller has at least one membership token
248
+ return IERC721(space).balanceOf(msg.sender) != 0;
249
+ }
250
+ }