@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,547 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {ITownsPointsBase} from "../../../../airdrop/points/ITownsPoints.sol";
6
+ import {IPartnerRegistry, IPartnerRegistryBase} from "../../../../factory/facets/partner/IPartnerRegistry.sol";
7
+ import {IEntitlement} from "../../../entitlements/IEntitlement.sol";
8
+ import {IRuleEntitlement} from "../../../entitlements/rule/IRuleEntitlement.sol";
9
+ import {IRolesBase} from "../../roles/IRoles.sol";
10
+ import {IMembership} from "../IMembership.sol";
11
+
12
+ // libraries
13
+ import {BasisPoints} from "../../../../utils/libraries/BasisPoints.sol";
14
+ import {CurrencyTransfer} from "../../../../utils/libraries/CurrencyTransfer.sol";
15
+ import {CustomRevert} from "../../../../utils/libraries/CustomRevert.sol";
16
+ import {Permissions} from "../../Permissions.sol";
17
+
18
+ // contracts
19
+ import {ERC5643Base} from "../../../../diamond/facets/token/ERC5643/ERC5643Base.sol";
20
+ import {ERC721ABase} from "../../../../diamond/facets/token/ERC721A/ERC721ABase.sol";
21
+ import {DispatcherBase} from "../../dispatcher/DispatcherBase.sol";
22
+ import {Entitled} from "../../Entitled.sol";
23
+ import {EntitlementGatedBase} from "../../gated/EntitlementGatedBase.sol";
24
+ import {PointsBase} from "../../points/PointsBase.sol";
25
+ import {PrepayBase} from "../../prepay/PrepayBase.sol";
26
+ import {ReferralsBase} from "../../referrals/ReferralsBase.sol";
27
+ import {RolesBase} from "../../roles/RolesBase.sol";
28
+ import {MembershipBase} from "../MembershipBase.sol";
29
+
30
+ /// @title MembershipJoin
31
+ /// @notice Handles the logic for joining a space, including entitlement checks and payment
32
+ /// processing
33
+ /// @dev Inherits from multiple base contracts to provide comprehensive membership functionality
34
+ abstract contract MembershipJoin is
35
+ IRolesBase,
36
+ IPartnerRegistryBase,
37
+ ERC5643Base,
38
+ MembershipBase,
39
+ ReferralsBase,
40
+ DispatcherBase,
41
+ RolesBase,
42
+ EntitlementGatedBase,
43
+ Entitled,
44
+ PrepayBase,
45
+ PointsBase,
46
+ ERC721ABase
47
+ {
48
+ using CustomRevert for bytes4;
49
+
50
+ /// @notice Constant representing the permission to join a space
51
+ bytes32 internal constant JOIN_SPACE = bytes32(abi.encodePacked(Permissions.JoinSpace));
52
+
53
+ /// @notice Constant representing the joinSpace(address) function selector
54
+ bytes4 internal constant JOIN_SPACE_SELECTOR = bytes4(keccak256("joinSpace(address)"));
55
+
56
+ /// @notice Encodes data for joining a space
57
+ /// @param selector The type of transaction (join with or without referral)
58
+ /// @param sender The address of the sender
59
+ /// @param receiver The address of the receiver
60
+ /// @param referralData Additional data for referrals
61
+ /// @return Encoded join space data
62
+ function _encodeJoinSpaceData(
63
+ bytes4 selector,
64
+ address sender,
65
+ address receiver,
66
+ bytes memory referralData
67
+ ) internal pure returns (bytes memory) {
68
+ return abi.encode(selector, sender, receiver, referralData);
69
+ }
70
+
71
+ /// @notice Calculates all pricing details for joining a space
72
+ /// @return joinDetails Struct containing all pricing information
73
+ function _getPricingDetails() internal view returns (PricingDetails memory joinDetails) {
74
+ uint256 totalSupply = _totalSupply();
75
+ uint256 membershipPrice = _getMembershipPrice(totalSupply);
76
+ uint256 freeAllocation = _getMembershipFreeAllocation();
77
+ uint256 prepaidSupply = _getPrepaidSupply();
78
+
79
+ joinDetails.basePrice = membershipPrice;
80
+ if (freeAllocation > totalSupply) {
81
+ return joinDetails;
82
+ }
83
+
84
+ // Check if this is a free join due to prepaid supply
85
+ if (prepaidSupply > 0) {
86
+ joinDetails.isPrepaid = true;
87
+ return joinDetails;
88
+ }
89
+
90
+ // Regular paid join
91
+ joinDetails.amountDue = membershipPrice;
92
+ joinDetails.shouldCharge = true;
93
+ }
94
+
95
+ /// @notice Handles the process of joining a space
96
+ /// @param receiver The address that will receive the membership token
97
+ function _joinSpace(address receiver) internal {
98
+ _validateJoinSpace(receiver);
99
+
100
+ PricingDetails memory joinDetails = _getPricingDetails();
101
+
102
+ // Validate payment if required
103
+ if (joinDetails.shouldCharge && msg.value < joinDetails.amountDue) {
104
+ Membership__InsufficientPayment.selector.revertWith();
105
+ }
106
+
107
+ // Consume prepaid membership if applicable
108
+ if (joinDetails.isPrepaid) _reducePrepay(1);
109
+
110
+ bytes32 transactionId = _registerTransaction(
111
+ receiver,
112
+ _encodeJoinSpaceData(JOIN_SPACE_SELECTOR, msg.sender, receiver, "")
113
+ );
114
+
115
+ (bool isEntitled, bool isCrosschainPending) = _checkEntitlement(
116
+ receiver,
117
+ msg.sender,
118
+ transactionId,
119
+ joinDetails.amountDue
120
+ );
121
+
122
+ if (!isCrosschainPending) {
123
+ if (isEntitled) {
124
+ if (joinDetails.shouldCharge) _chargeForJoinSpace(transactionId, joinDetails);
125
+ _refundBalance(transactionId, receiver);
126
+ _issueToken(receiver);
127
+ } else {
128
+ _rejectMembership(transactionId, receiver);
129
+ }
130
+ }
131
+ }
132
+
133
+ /// @notice Handles the process of joining a space with a referral
134
+ /// @param receiver The address that will receive the membership token
135
+ /// @param referral The referral information
136
+ function _joinSpaceWithReferral(address receiver, ReferralTypes memory referral) internal {
137
+ _validateJoinSpace(receiver);
138
+
139
+ PricingDetails memory joinDetails = _getPricingDetails();
140
+
141
+ // Validate payment if required
142
+ if (joinDetails.shouldCharge && msg.value < joinDetails.amountDue) {
143
+ Membership__InsufficientPayment.selector.revertWith();
144
+ }
145
+
146
+ // Consume prepaid membership if applicable
147
+ if (joinDetails.isPrepaid) {
148
+ _reducePrepay(1);
149
+ }
150
+
151
+ _validateUserReferral(receiver, referral);
152
+
153
+ bytes memory referralData = abi.encode(referral);
154
+
155
+ bytes4 selector = IMembership.joinSpaceWithReferral.selector;
156
+
157
+ bytes32 transactionId = _registerTransaction(
158
+ receiver,
159
+ _encodeJoinSpaceData(selector, msg.sender, receiver, referralData)
160
+ );
161
+
162
+ (bool isEntitled, bool isCrosschainPending) = _checkEntitlement(
163
+ receiver,
164
+ msg.sender,
165
+ transactionId,
166
+ joinDetails.amountDue
167
+ );
168
+
169
+ if (!isCrosschainPending) {
170
+ if (isEntitled) {
171
+ if (joinDetails.shouldCharge)
172
+ _chargeForJoinSpaceWithReferral(transactionId, joinDetails);
173
+
174
+ _refundBalance(transactionId, receiver);
175
+ _issueToken(receiver);
176
+ } else {
177
+ _rejectMembership(transactionId, receiver);
178
+ }
179
+ }
180
+ }
181
+
182
+ function _rejectMembership(bytes32 transactionId, address receiver) internal {
183
+ _deleteCapturedData(transactionId);
184
+ _refundBalance(transactionId, receiver);
185
+ emit MembershipTokenRejected(receiver);
186
+ }
187
+
188
+ function _validateUserReferral(address receiver, ReferralTypes memory referral) internal view {
189
+ if (referral.userReferral != address(0)) {
190
+ if (referral.userReferral == receiver || referral.userReferral == msg.sender) {
191
+ Membership__InvalidAddress.selector.revertWith();
192
+ }
193
+ }
194
+ }
195
+
196
+ /// @notice Checks if a user is entitled to join the space and handles the entitlement process
197
+ /// @dev This function checks both local and crosschain entitlements
198
+ /// @param receiver The address of the user trying to join the space
199
+ /// @param transactionId The unique identifier for this join transaction
200
+ /// @return isEntitled A boolean indicating whether the user is entitled to join
201
+ /// @return isCrosschainPending A boolean indicating if a crosschain entitlement check is
202
+ /// pending
203
+ function _checkEntitlement(
204
+ address receiver,
205
+ address sender,
206
+ bytes32 transactionId,
207
+ uint256 requiredAmount
208
+ ) internal virtual returns (bool isEntitled, bool isCrosschainPending) {
209
+ IRolesBase.Role[] memory roles = _getRolesWithPermission(Permissions.JoinSpace);
210
+
211
+ // PHASE 1: Check LOCAL entitlements first (no payment needed)
212
+ if (_checkLocalEntitlements(roles, receiver)) return (true, false);
213
+
214
+ // PHASE 2: No local entitlements passed - check crosschain entitlements
215
+ return _checkCrosschainEntitlements(roles, receiver, sender, transactionId, requiredAmount);
216
+ }
217
+
218
+ /// @notice Checks local entitlements
219
+ /// @param receiver The address to check entitlements for
220
+ /// @return isLocallyEntitled True if user has local entitlements
221
+ function _checkLocalEntitlements(
222
+ IRolesBase.Role[] memory roles,
223
+ address receiver
224
+ ) internal view returns (bool isLocallyEntitled) {
225
+ address[] memory linkedWallets = _getLinkedWalletsWithUser(receiver);
226
+
227
+ for (uint256 i; i < roles.length; ++i) {
228
+ if (roles[i].disabled) continue;
229
+
230
+ for (uint256 j; j < roles[i].entitlements.length; ++j) {
231
+ IEntitlement entitlement = IEntitlement(roles[i].entitlements[j]);
232
+
233
+ // Check local entitlements first
234
+ if (
235
+ !entitlement.isCrosschain() &&
236
+ entitlement.isEntitled(IN_TOWN, linkedWallets, JOIN_SPACE)
237
+ ) {
238
+ // Local entitlement passed - return true (payment handled by existing flow)
239
+ return true;
240
+ }
241
+ }
242
+ }
243
+ return false;
244
+ }
245
+
246
+ /// @notice Handles crosschain entitlement checks with proper payment distribution
247
+ /// @param receiver The address to check entitlements for
248
+ /// @param sender The address sending the transaction
249
+ /// @param transactionId The transaction identifier
250
+ /// @param requiredAmount The required payment amount
251
+ /// @return isEntitled Whether user is entitled (always false for crosschain)
252
+ /// @return isCrosschainPending Whether crosschain checks are pending
253
+ function _checkCrosschainEntitlements(
254
+ IRolesBase.Role[] memory roles,
255
+ address receiver,
256
+ address sender,
257
+ bytes32 transactionId,
258
+ uint256 requiredAmount
259
+ ) internal returns (bool isEntitled, bool isCrosschainPending) {
260
+ bool paymentSent = false;
261
+
262
+ for (uint256 i; i < roles.length; ++i) {
263
+ if (roles[i].disabled) continue;
264
+
265
+ for (uint256 j; j < roles[i].entitlements.length; ++j) {
266
+ IEntitlement entitlement = IEntitlement(roles[i].entitlements[j]);
267
+
268
+ if (entitlement.isCrosschain()) {
269
+ if (!paymentSent) {
270
+ // Send only the required amount to crosschain check
271
+ // Excess will be handled by existing refund mechanisms
272
+ _requestEntitlementCheckV2(
273
+ receiver,
274
+ sender,
275
+ transactionId,
276
+ IRuleEntitlement(address(entitlement)),
277
+ roles[i].id,
278
+ requiredAmount
279
+ );
280
+ paymentSent = true;
281
+ } else {
282
+ _requestEntitlementCheckV2(
283
+ receiver,
284
+ sender,
285
+ transactionId,
286
+ IRuleEntitlement(address(entitlement)),
287
+ roles[i].id,
288
+ 0
289
+ );
290
+ }
291
+ isCrosschainPending = true;
292
+ }
293
+ }
294
+ }
295
+
296
+ return (false, isCrosschainPending);
297
+ }
298
+
299
+ /// @notice Processes the charge for joining a space without referral
300
+ /// @param transactionId The unique identifier for this join transaction
301
+ /// @param joinDetails The pricing details for this join
302
+ function _chargeForJoinSpace(
303
+ bytes32 transactionId,
304
+ PricingDetails memory joinDetails
305
+ ) internal {
306
+ (bytes4 selector, address sender, address receiver, ) = abi.decode(
307
+ _getCapturedData(transactionId),
308
+ (bytes4, address, address, bytes)
309
+ );
310
+
311
+ if (selector != JOIN_SPACE_SELECTOR) {
312
+ Membership__InvalidTransactionType.selector.revertWith();
313
+ }
314
+
315
+ uint256 protocolFee = _collectProtocolFee(sender, joinDetails.basePrice);
316
+ uint256 ownerProceeds = joinDetails.amountDue - protocolFee;
317
+
318
+ _afterChargeForJoinSpace(
319
+ transactionId,
320
+ sender,
321
+ receiver,
322
+ joinDetails.amountDue,
323
+ ownerProceeds,
324
+ joinDetails.basePrice
325
+ );
326
+ }
327
+
328
+ /// @notice Processes the charge for joining a space with referral
329
+ /// @param transactionId The unique identifier for this join transaction
330
+ /// @param joinDetails The pricing details for this join
331
+ function _chargeForJoinSpaceWithReferral(
332
+ bytes32 transactionId,
333
+ PricingDetails memory joinDetails
334
+ ) internal {
335
+ (bytes4 selector, address sender, address receiver, bytes memory referralData) = abi.decode(
336
+ _getCapturedData(transactionId),
337
+ (bytes4, address, address, bytes)
338
+ );
339
+
340
+ if (selector != IMembership.joinSpaceWithReferral.selector) {
341
+ Membership__InvalidTransactionType.selector.revertWith();
342
+ }
343
+
344
+ ReferralTypes memory referral = abi.decode(referralData, (ReferralTypes));
345
+
346
+ uint256 ownerProceeds;
347
+ {
348
+ uint256 protocolFee = _collectProtocolFee(sender, joinDetails.basePrice);
349
+
350
+ uint256 partnerFee = _collectPartnerFee(
351
+ sender,
352
+ referral.partner,
353
+ joinDetails.basePrice
354
+ );
355
+
356
+ uint256 referralFee = _collectReferralCodeFee(
357
+ sender,
358
+ referral.userReferral,
359
+ referral.referralCode,
360
+ joinDetails.basePrice
361
+ );
362
+
363
+ ownerProceeds = joinDetails.amountDue - protocolFee - partnerFee - referralFee;
364
+ }
365
+
366
+ _afterChargeForJoinSpace(
367
+ transactionId,
368
+ sender,
369
+ receiver,
370
+ joinDetails.amountDue,
371
+ ownerProceeds,
372
+ joinDetails.basePrice
373
+ );
374
+ }
375
+
376
+ function _afterChargeForJoinSpace(
377
+ bytes32 transactionId,
378
+ address payer,
379
+ address receiver,
380
+ uint256 paymentRequired,
381
+ uint256 ownerProceeds,
382
+ uint256 membershipPrice
383
+ ) internal {
384
+ // account for owner's proceeds
385
+ if (ownerProceeds != 0) _transferIn(payer, ownerProceeds);
386
+
387
+ _releaseCapturedValue(transactionId, paymentRequired);
388
+ _deleteCapturedData(transactionId);
389
+
390
+ _mintMembershipPoints(receiver, membershipPrice);
391
+ }
392
+
393
+ /// @notice Issues a membership token to the receiver
394
+ /// @param receiver The address that will receive the membership token
395
+ function _issueToken(address receiver) internal {
396
+ // get token id
397
+ uint256 tokenId = _nextTokenId();
398
+
399
+ // set renewal price for token
400
+ _setMembershipRenewalPrice(tokenId, _getMembershipPrice(_totalSupply()));
401
+
402
+ // mint membership
403
+ _safeMint(receiver, 1);
404
+
405
+ // set expiration of membership
406
+ _renewSubscription(tokenId, _getMembershipDuration());
407
+
408
+ // emit event
409
+ emit MembershipTokenIssued(receiver, tokenId);
410
+ }
411
+
412
+ /// @notice Validates if a user can join the space
413
+ /// @param receiver The address that will receive the membership token
414
+ function _validateJoinSpace(address receiver) internal view {
415
+ if (receiver == address(0)) Membership__InvalidAddress.selector.revertWith();
416
+ uint256 membershipSupplyLimit = _getMembershipSupplyLimit();
417
+ if (membershipSupplyLimit != 0 && _totalSupply() >= membershipSupplyLimit) {
418
+ Membership__MaxSupplyReached.selector.revertWith();
419
+ }
420
+ }
421
+
422
+ /// @notice Refunds the balance to the sender if necessary
423
+ /// @param transactionId The unique identifier for this join transaction
424
+ /// @param sender The address of the sender to refund
425
+ function _refundBalance(bytes32 transactionId, address sender) internal {
426
+ uint256 userValue = _getCapturedValue(transactionId);
427
+ if (userValue > 0) {
428
+ _releaseCapturedValue(transactionId, userValue);
429
+ CurrencyTransfer.transferCurrency(
430
+ _getMembershipCurrency(),
431
+ address(this),
432
+ sender,
433
+ userValue
434
+ );
435
+ }
436
+ }
437
+
438
+ /// @notice Collects the referral fee if applicable
439
+ /// @param payer The address of the payer
440
+ /// @param referralCode The referral code used
441
+ /// @param membershipPrice The price of the membership
442
+ /// @return referralFee The amount of referral fee collected
443
+ function _collectReferralCodeFee(
444
+ address payer,
445
+ address userReferral,
446
+ string memory referralCode,
447
+ uint256 membershipPrice
448
+ ) internal returns (uint256 referralFee) {
449
+ if (bytes(referralCode).length != 0) {
450
+ Referral memory referral = _referralInfo(referralCode);
451
+
452
+ if (referral.recipient == address(0) || referral.basisPoints == 0) return 0;
453
+
454
+ referralFee = BasisPoints.calculate(membershipPrice, referral.basisPoints);
455
+
456
+ CurrencyTransfer.transferCurrency(
457
+ _getMembershipCurrency(),
458
+ payer,
459
+ referral.recipient,
460
+ referralFee
461
+ );
462
+ } else if (userReferral != address(0)) {
463
+ if (userReferral == payer) return 0;
464
+
465
+ referralFee = BasisPoints.calculate(membershipPrice, _defaultBpsFee());
466
+
467
+ CurrencyTransfer.transferCurrency(
468
+ _getMembershipCurrency(),
469
+ payer,
470
+ userReferral,
471
+ referralFee
472
+ );
473
+ }
474
+ }
475
+
476
+ /// @notice Collects the partner fee if applicable
477
+ /// @param payer The address of the payer
478
+ /// @param partner The address of the partner
479
+ /// @param membershipPrice The price of the membership
480
+ /// @return partnerFee The amount of partner fee collected
481
+ function _collectPartnerFee(
482
+ address payer,
483
+ address partner,
484
+ uint256 membershipPrice
485
+ ) internal returns (uint256 partnerFee) {
486
+ if (partner == address(0)) return 0;
487
+
488
+ Partner memory partnerInfo = IPartnerRegistry(_getSpaceFactory()).partnerInfo(partner);
489
+
490
+ if (partnerInfo.fee == 0) return 0;
491
+
492
+ partnerFee = BasisPoints.calculate(membershipPrice, partnerInfo.fee);
493
+
494
+ CurrencyTransfer.transferCurrency(
495
+ _getMembershipCurrency(),
496
+ payer,
497
+ partnerInfo.recipient,
498
+ partnerFee
499
+ );
500
+ }
501
+
502
+ function _renewMembership(address payer, uint256 tokenId) internal {
503
+ address receiver = _ownerOf(tokenId);
504
+
505
+ if (receiver == address(0)) Membership__InvalidAddress.selector.revertWith();
506
+
507
+ uint256 duration = _getMembershipDuration();
508
+ uint256 membershipPrice = _getMembershipRenewalPrice(tokenId, _totalSupply());
509
+
510
+ if (membershipPrice > msg.value) Membership__InvalidPayment.selector.revertWith();
511
+
512
+ _mintMembershipPoints(receiver, membershipPrice);
513
+
514
+ uint256 protocolFee = _collectProtocolFee(payer, membershipPrice);
515
+
516
+ uint256 remainingDue = membershipPrice - protocolFee;
517
+ if (remainingDue > 0) _transferIn(payer, remainingDue);
518
+
519
+ uint256 excess = msg.value - membershipPrice;
520
+ if (excess > 0) {
521
+ CurrencyTransfer.transferCurrency(
522
+ _getMembershipCurrency(),
523
+ address(this),
524
+ payer,
525
+ excess
526
+ );
527
+ }
528
+
529
+ _renewSubscription(tokenId, uint64(duration));
530
+ }
531
+
532
+ /// @notice Mints points to a member based on their paid amount
533
+ /// @dev This function handles point minting for both new joins and renewals
534
+ /// @param receiver The address receiving the points
535
+ /// @param paidAmount The amount paid for membership
536
+ function _mintMembershipPoints(address receiver, uint256 paidAmount) internal {
537
+ // calculate points and credit them
538
+ address airdropDiamond = _getAirdropDiamond();
539
+ uint256 points = _getPoints(
540
+ airdropDiamond,
541
+ ITownsPointsBase.Action.JoinSpace,
542
+ abi.encode(paidAmount)
543
+ );
544
+ _mintPoints(airdropDiamond, receiver, points);
545
+ _mintPoints(airdropDiamond, _owner(), points);
546
+ }
547
+ }
@@ -0,0 +1,9 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ interface IMembershipMetadata {
5
+ /// @notice Emits an event to trigger metadata refresh when the space info is updated
6
+ function refreshMetadata() external;
7
+
8
+ function tokenURI(uint256 tokenId) external view returns (string memory);
9
+ }
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ import {IMembershipMetadata} from "./IMembershipMetadata.sol";
7
+ import {IERC4906} from "@openzeppelin/contracts/interfaces/IERC4906.sol";
8
+ import {IERC721A} from "src/diamond/facets/token/ERC721A/IERC721A.sol";
9
+
10
+ // libraries
11
+ import {TokenOwnableStorage} from "@towns-protocol/diamond/src/facets/ownable/token/TokenOwnableStorage.sol";
12
+ import {LibString} from "solady/utils/LibString.sol";
13
+
14
+ // contracts
15
+
16
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
17
+ import {ERC721ABase} from "src/diamond/facets/token/ERC721A/ERC721ABase.sol";
18
+
19
+ contract MembershipMetadata is IMembershipMetadata, ERC721ABase, Facet {
20
+ /// @inheritdoc IMembershipMetadata
21
+ function refreshMetadata() external {
22
+ emit IERC4906.BatchMetadataUpdate(0, type(uint256).max);
23
+ }
24
+
25
+ function tokenURI(uint256 tokenId) public view returns (string memory) {
26
+ if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
27
+ TokenOwnableStorage.Layout storage ds = TokenOwnableStorage.layout();
28
+ string memory baseURI = IERC721A(ds.collection).tokenURI(ds.tokenId);
29
+ string memory tokenIdStr = LibString.toString(tokenId);
30
+ return string.concat(baseURI, "/token/", tokenIdStr);
31
+ }
32
+ }
@@ -0,0 +1,18 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+
10
+ interface IMembershipPricing {
11
+ function name() external view returns (string memory);
12
+
13
+ function description() external view returns (string memory);
14
+
15
+ function setPrice(uint256 price) external;
16
+
17
+ function getPrice(uint256 freeAllocation, uint256 totalMinted) external view returns (uint256);
18
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IMembershipPricing} from "src/spaces/facets/membership/pricing/IMembershipPricing.sol";
6
+
7
+ // libraries
8
+ import {FixedPricingStorage} from "./FixedPricingStorage.sol";
9
+
10
+ // contracts
11
+ import {IntrospectionFacet} from "@towns-protocol/diamond/src/facets/introspection/IntrospectionFacet.sol";
12
+
13
+ contract FixedPricing is IMembershipPricing, IntrospectionFacet {
14
+ string public name = "FixedPricing";
15
+ string public description = "Fixed pricing for membership";
16
+
17
+ constructor() {
18
+ __IntrospectionBase_init();
19
+ _addInterface(type(IMembershipPricing).interfaceId);
20
+ }
21
+
22
+ function setPrice(uint256 price) external {
23
+ FixedPricingStorage.layout().priceBySpace[msg.sender] = price;
24
+ }
25
+
26
+ function getPrice(uint256, uint256) external view returns (uint256) {
27
+ return FixedPricingStorage.layout().priceBySpace[msg.sender];
28
+ }
29
+ }
@@ -0,0 +1,27 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+
10
+ library FixedPricingStorage {
11
+ // keccak256(abi.encode(uint256(keccak256("spaces.facets.membership.pricing.fixed.storage")) -
12
+ // 1))
13
+ // & ~bytes32(uint256(0xff))
14
+ bytes32 internal constant STORAGE_SLOT =
15
+ 0xd905de679d8ee984e33da0498883a319db2532b35c6b45e3d77ada3832c5b000;
16
+
17
+ struct Layout {
18
+ mapping(address => uint256) priceBySpace;
19
+ }
20
+
21
+ function layout() internal pure returns (Layout storage ds) {
22
+ bytes32 slot = STORAGE_SLOT;
23
+ assembly {
24
+ ds.slot := slot
25
+ }
26
+ }
27
+ }