@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,290 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {ITownsPointsBase} from "../../../airdrop/points/ITownsPoints.sol";
6
+ import {IPlatformRequirements} from "../../../factory/facets/platform/requirements/IPlatformRequirements.sol";
7
+ import {ISwapRouter} from "../../../router/ISwapRouter.sol";
8
+ import {ISwapFacet} from "./ISwapFacet.sol";
9
+
10
+ // libraries
11
+ import {BasisPoints} from "../../../utils/libraries/BasisPoints.sol";
12
+ import {CurrencyTransfer} from "../../../utils/libraries/CurrencyTransfer.sol";
13
+ import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
14
+ import {DependencyLib} from "../DependencyLib.sol";
15
+ import {MembershipStorage} from "../membership/MembershipStorage.sol";
16
+ import {SwapFacetStorage} from "./SwapFacetStorage.sol";
17
+ import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol";
18
+ import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
19
+
20
+ // contracts
21
+ import {Entitled} from "../Entitled.sol";
22
+ import {PointsBase} from "../points/PointsBase.sol";
23
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
24
+ import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
25
+
26
+ /**
27
+ * @title SwapFacet
28
+ * @notice Diamond facet for executing swaps within a space with configurable fees and poster handling
29
+ * @dev This facet extends SwapRouter functionality with space-specific features:
30
+ *
31
+ * Standard Swaps (`executeSwap`):
32
+ * - Space membership validation required for all callers
33
+ * - Configurable poster fees (to space treasury or forwarded to poster)
34
+ * - Smart ETH refund logic accounts for poster fees when poster is space
35
+ * - Points minting for ETH-involved swaps
36
+ *
37
+ * Permit2 Swaps (`executeSwapWithPermit`):
38
+ * - All standard swap features plus Permit2 security enhancements
39
+ * - Cryptographic binding prevents fee manipulation attacks
40
+ *
41
+ * Space-Specific Features:
42
+ * - Owner-configurable poster fee rates and forwarding behavior via `setSwapFeeConfig`
43
+ * - Automatic fee collection to space treasury when poster equals space address
44
+ * - Smart refund logic preserves space fees during partial ETH swaps
45
+ * - Integration with space entitlement and membership validation systems
46
+ * - Diamond pattern integration for upgradeable space functionality
47
+ */
48
+ contract SwapFacet is ISwapFacet, ReentrancyGuardTransient, Entitled, PointsBase, Facet {
49
+ using CustomRevert for bytes4;
50
+ using SafeTransferLib for address;
51
+
52
+ /// @notice Maximum fee in basis points (2%)
53
+ uint16 internal constant MAX_FEE_BPS = 200;
54
+
55
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
56
+ /* ADMIN FUNCTIONS */
57
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
58
+
59
+ /// @inheritdoc ISwapFacet
60
+ function setSwapFeeConfig(uint16 posterFeeBps, bool forwardPosterFee) external onlyOwner {
61
+ // get protocol fee for validation
62
+ IPlatformRequirements platform = _getPlatformRequirements();
63
+ (uint16 protocolBps, ) = platform.getSwapFees();
64
+
65
+ // ensure total fee is reasonable
66
+ if (protocolBps + posterFeeBps > MAX_FEE_BPS) {
67
+ SwapFacet__TotalFeeTooHigh.selector.revertWith();
68
+ }
69
+
70
+ SwapFacetStorage.Layout storage ds = SwapFacetStorage.layout();
71
+ (ds.posterFeeBps, ds.forwardPosterFee) = (posterFeeBps, forwardPosterFee);
72
+
73
+ emit SwapFeeConfigUpdated(posterFeeBps, forwardPosterFee);
74
+ }
75
+
76
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
77
+ /* SWAP */
78
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
79
+
80
+ /// @inheritdoc ISwapFacet
81
+ function executeSwap(
82
+ ExactInputParams calldata params,
83
+ RouterParams calldata routerParams,
84
+ address poster
85
+ ) external payable nonReentrant returns (uint256 amountOut) {
86
+ address swapRouter = _validateSwapPrerequisites(poster);
87
+
88
+ // create mutable copy in memory to modify amountIn for fee-on-transfer tokens
89
+ ExactInputParams memory paramsMemory = params;
90
+
91
+ // handle ERC20 transfers before calling SwapRouter
92
+ bool isNativeToken = params.tokenIn == CurrencyTransfer.NATIVE_TOKEN;
93
+
94
+ // take snapshot of balance BEFORE receiving user tokens for refund calculation
95
+ uint256 tokenInBalanceBefore;
96
+ if (!isNativeToken) {
97
+ // use the actual received amount to handle fee-on-transfer tokens
98
+ tokenInBalanceBefore = params.tokenIn.balanceOf(address(this));
99
+ params.tokenIn.safeTransferFrom(msg.sender, address(this), params.amountIn);
100
+ // update amountIn based on the actual balance after transfer
101
+ paramsMemory.amountIn = params.tokenIn.balanceOf(address(this)) - tokenInBalanceBefore;
102
+
103
+ // approve SwapRouter to spend the tokens
104
+ params.tokenIn.safeApprove(swapRouter, paramsMemory.amountIn);
105
+ } else {
106
+ // for ETH, msg.value is already included in balance, so subtract it
107
+ tokenInBalanceBefore = address(this).balance - msg.value;
108
+ }
109
+
110
+ // execute swap through the router
111
+ // forwarding `msg.value` may introduce double-spending if used with `multicall`
112
+ // which has been handled by Solady Multicallable
113
+ uint256 protocolFee;
114
+ (amountOut, protocolFee) = ISwapRouter(swapRouter).executeSwap{value: msg.value}(
115
+ paramsMemory,
116
+ routerParams,
117
+ poster
118
+ );
119
+
120
+ // handle refunds of unconsumed input tokens
121
+ _handleRefunds(params.tokenIn, tokenInBalanceBefore, poster);
122
+
123
+ // reset approval for ERC20 tokens
124
+ if (!isNativeToken) params.tokenIn.safeApprove(swapRouter, 0);
125
+
126
+ _mintPointsAndEmitSwapEvent(params, amountOut, protocolFee, poster, msg.sender);
127
+ }
128
+
129
+ /// @inheritdoc ISwapFacet
130
+ /// @dev Permit is forwarded directly to SwapRouter which handles all token operations,
131
+ /// e.g. Permit2 transfers, approvals, refunds
132
+ function executeSwapWithPermit(
133
+ ExactInputParams calldata params,
134
+ RouterParams calldata routerParams,
135
+ FeeConfig calldata posterFee,
136
+ Permit2Params calldata permit
137
+ ) external payable nonReentrant returns (uint256 amountOut) {
138
+ // Permit2 swaps do not support ETH
139
+ if (msg.value != 0) SwapFacet__UnexpectedETH.selector.revertWith();
140
+
141
+ address swapRouter = _validateSwapPrerequisites(posterFee.recipient);
142
+
143
+ // execute swap through the router with permit
144
+ uint256 protocolFee;
145
+ (amountOut, protocolFee) = ISwapRouter(swapRouter).executeSwapWithPermit(
146
+ params,
147
+ routerParams,
148
+ posterFee,
149
+ permit
150
+ );
151
+
152
+ _mintPointsAndEmitSwapEvent(
153
+ params,
154
+ amountOut,
155
+ protocolFee,
156
+ posterFee.recipient,
157
+ permit.owner
158
+ );
159
+ }
160
+
161
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
162
+ /* GETTERS */
163
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
164
+
165
+ /// @inheritdoc ISwapFacet
166
+ function getSwapRouter() public view returns (address) {
167
+ return DependencyLib.getDependency(MembershipStorage.layout(), DependencyLib.SWAP_ROUTER);
168
+ }
169
+
170
+ /// @inheritdoc ISwapFacet
171
+ function getSwapFees()
172
+ public
173
+ view
174
+ returns (uint16 protocolBps, uint16 posterBps, bool forwardPosterFee)
175
+ {
176
+ SwapFacetStorage.Layout storage ds = SwapFacetStorage.layout();
177
+
178
+ // get protocolBps and posterBps from protocol config
179
+ IPlatformRequirements platform = _getPlatformRequirements();
180
+ (protocolBps, posterBps) = platform.getSwapFees();
181
+
182
+ uint16 spacePosterBps;
183
+ (spacePosterBps, forwardPosterFee) = (ds.posterFeeBps, ds.forwardPosterFee);
184
+
185
+ // if poster fee is forwarded or spacePosterBps is set, use spacePosterBps
186
+ if (forwardPosterFee || spacePosterBps != 0) posterBps = spacePosterBps;
187
+ }
188
+
189
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
190
+ /* INTERNAL */
191
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
192
+
193
+ /// @notice Mint points for ETH swaps and emit swap events
194
+ /// @param params The swap parameters for event emission
195
+ /// @param amountOut The amount of output tokens received
196
+ /// @param protocolFee The protocol fee collected for points calculation
197
+ /// @param poster The swap poster address
198
+ /// @param payer The address that should receive the points
199
+ function _mintPointsAndEmitSwapEvent(
200
+ ExactInputParams calldata params,
201
+ uint256 amountOut,
202
+ uint256 protocolFee,
203
+ address poster,
204
+ address payer
205
+ ) internal {
206
+ // mint points based on the protocol fee if ETH is involved
207
+ if (
208
+ params.tokenIn == CurrencyTransfer.NATIVE_TOKEN ||
209
+ params.tokenOut == CurrencyTransfer.NATIVE_TOKEN
210
+ ) {
211
+ address airdropDiamond = _getAirdropDiamond();
212
+ uint256 points = _getPoints(
213
+ airdropDiamond,
214
+ ITownsPointsBase.Action.Swap,
215
+ abi.encode(protocolFee)
216
+ );
217
+ _mintPoints(airdropDiamond, payer, points);
218
+ }
219
+
220
+ emit SwapExecuted(
221
+ params.recipient,
222
+ params.tokenIn,
223
+ params.tokenOut,
224
+ params.amountIn,
225
+ amountOut,
226
+ poster
227
+ );
228
+ }
229
+
230
+ /// @notice Handles refunds of unconsumed input tokens back to the caller
231
+ /// @param tokenIn The input token address
232
+ /// @param tokenInBalanceBefore The balance before receiving tokens from user
233
+ /// @param poster The poster address for this swap
234
+ function _handleRefunds(
235
+ address tokenIn,
236
+ uint256 tokenInBalanceBefore,
237
+ address poster
238
+ ) internal {
239
+ uint256 currentBalance = _getBalance(tokenIn);
240
+
241
+ // calculate base refund amount
242
+ uint256 refundAmount = FixedPointMathLib.zeroFloorSub(currentBalance, tokenInBalanceBefore);
243
+
244
+ // for ETH, subtract poster fee if it was collected to space
245
+ // this happens when poster is the space itself (regardless of forwardPosterFee setting)
246
+ if (tokenIn == CurrencyTransfer.NATIVE_TOKEN && poster == address(this)) {
247
+ // get the poster fee that was collected to space
248
+ (, uint16 posterBps, ) = getSwapFees();
249
+ uint256 posterFee = BasisPoints.calculate(msg.value, posterBps);
250
+
251
+ // subtract poster fee from refund since it should stay in space
252
+ refundAmount = FixedPointMathLib.zeroFloorSub(refundAmount, posterFee);
253
+ }
254
+
255
+ CurrencyTransfer.transferCurrency(tokenIn, address(this), msg.sender, refundAmount);
256
+ }
257
+
258
+ /// @notice Validates swap prerequisites (membership, SwapRouter availability, and poster address)
259
+ /// @param poster The poster address to validate
260
+ /// @return swapRouter The address of the SwapRouter to use
261
+ function _validateSwapPrerequisites(address poster) internal view returns (address swapRouter) {
262
+ _validateMembership(msg.sender);
263
+
264
+ swapRouter = getSwapRouter();
265
+ if (swapRouter == address(0)) SwapFacet__SwapRouterNotSet.selector.revertWith();
266
+
267
+ // validate poster address based on fee configuration
268
+ if (!(_isForwardPosterFee() || poster == address(this))) {
269
+ SwapFacet__InvalidPosterInput.selector.revertWith();
270
+ }
271
+ }
272
+
273
+ function _getPlatformRequirements() internal view returns (IPlatformRequirements) {
274
+ return IPlatformRequirements(MembershipStorage.layout().spaceFactory);
275
+ }
276
+
277
+ /// @notice Gets the balance of a token for this contract
278
+ /// @param token The token to check
279
+ /// @return uint256 The balance
280
+ function _getBalance(address token) internal view returns (uint256) {
281
+ if (token == CurrencyTransfer.NATIVE_TOKEN) return address(this).balance;
282
+ return token.balanceOf(address(this));
283
+ }
284
+
285
+ /// @notice Checks if poster fees should be forwarded to the poster
286
+ /// @return bool True if poster fees are forwarded, false if they go to the space
287
+ function _isForwardPosterFee() internal view returns (bool) {
288
+ return SwapFacetStorage.layout().forwardPosterFee;
289
+ }
290
+ }
@@ -0,0 +1,24 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ /// @title SwapFacetStorage
5
+ /// @notice Storage layout for the SwapFacet contract
6
+ library SwapFacetStorage {
7
+ // keccak256(abi.encode(uint256(keccak256("spaces.facets.swap.storage")) - 1)) &
8
+ // ~bytes32(uint256(0xff))
9
+ bytes32 internal constant STORAGE_SLOT =
10
+ 0xf363e6f383c163fac4382e7bd60c54a795a129059b7601463644e52990dfaf00;
11
+
12
+ struct Layout {
13
+ /// @notice Poster fee in basis points (space-specific)
14
+ uint16 posterFeeBps;
15
+ /// @notice Whether to forward the poster fee to the poster (default: false, fees go to space)
16
+ bool forwardPosterFee;
17
+ }
18
+
19
+ function layout() internal pure returns (Layout storage l) {
20
+ assembly {
21
+ l.slot := STORAGE_SLOT
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,80 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+
10
+ interface ITippingBase {
11
+ // =============================================================
12
+ // Structs
13
+ // =============================================================
14
+
15
+ struct TipRequest {
16
+ address receiver;
17
+ uint256 tokenId;
18
+ address currency;
19
+ uint256 amount;
20
+ bytes32 messageId;
21
+ bytes32 channelId;
22
+ }
23
+
24
+ // =============================================================
25
+ // Events
26
+ // =============================================================
27
+
28
+ event Tip(
29
+ uint256 indexed tokenId,
30
+ address indexed currency,
31
+ address sender,
32
+ address receiver,
33
+ uint256 amount,
34
+ bytes32 messageId,
35
+ bytes32 channelId
36
+ );
37
+
38
+ // =============================================================
39
+ // Errors
40
+ // =============================================================
41
+
42
+ error TokenDoesNotExist();
43
+ error ReceiverIsNotMember();
44
+ error CannotTipSelf();
45
+ error AmountIsZero();
46
+ error CurrencyIsZero();
47
+ }
48
+
49
+ interface ITipping is ITippingBase {
50
+ /// @notice Sends a tip to a space member
51
+ /// @param tipRequest The tip request containing token ID, currency, amount, message ID and
52
+ /// channel ID
53
+ /// @dev Requires sender and receiver to be members of the space
54
+ /// @dev Requires amount > 0 and valid currency address
55
+ /// @dev Emits Tip event
56
+ function tip(TipRequest calldata tipRequest) external payable;
57
+
58
+ /// @notice Gets the total tips received for a token ID in a specific currency
59
+ /// @param tokenId The token ID to get tips for
60
+ /// @param currency The currency address to get tips in
61
+ /// @return The total amount of tips received in the specified currency
62
+ function tipsByCurrencyAndTokenId(
63
+ uint256 tokenId,
64
+ address currency
65
+ ) external view returns (uint256);
66
+
67
+ /// @notice Gets the list of currencies that have been tipped to the space
68
+ /// @return An array of currency addresses
69
+ function tippingCurrencies() external view returns (address[] memory);
70
+
71
+ /// @notice Gets the total number of tips received in a specific currency
72
+ /// @param currency The currency address to get tips for
73
+ /// @return The total number of tips received in the specified currency
74
+ function totalTipsByCurrency(address currency) external view returns (uint256);
75
+
76
+ /// @notice Gets the total amount of tips received in a specific currency
77
+ /// @param currency The currency address to get tips for
78
+ /// @return The total amount of tips received in the specified currency
79
+ function tipAmountByCurrency(address currency) external view returns (uint256);
80
+ }
@@ -0,0 +1,73 @@
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
+ import {CurrencyTransfer} from "src/utils/libraries/CurrencyTransfer.sol";
9
+ // contracts
10
+
11
+ library TippingBase {
12
+ using EnumerableSet for EnumerableSet.AddressSet;
13
+
14
+ // keccak256(abi.encode(uint256(keccak256("spaces.facets.tipping.storage")) - 1)) &
15
+ // ~bytes32(uint256(0xff))
16
+ bytes32 internal constant STORAGE_SLOT =
17
+ 0xb6cb334a9eea0cca2581db4520b45ac6f03de8e3927292302206bb82168be300;
18
+
19
+ struct TippingStats {
20
+ uint256 totalTips;
21
+ uint256 tipAmount;
22
+ }
23
+
24
+ struct Layout {
25
+ EnumerableSet.AddressSet currencies;
26
+ mapping(uint256 tokenId => mapping(address currency => uint256 amount)) tipsByCurrencyByTokenId;
27
+ mapping(address currency => TippingStats) tippingStatsByCurrency;
28
+ }
29
+
30
+ function layout() internal pure returns (Layout storage l) {
31
+ assembly {
32
+ l.slot := STORAGE_SLOT
33
+ }
34
+ }
35
+
36
+ function tip(
37
+ address sender,
38
+ address receiver,
39
+ uint256 tokenId,
40
+ address currency,
41
+ uint256 amount
42
+ ) internal {
43
+ Layout storage ds = layout();
44
+
45
+ ds.currencies.add(currency);
46
+ ds.tipsByCurrencyByTokenId[tokenId][currency] += amount;
47
+
48
+ TippingStats storage stats = ds.tippingStatsByCurrency[currency];
49
+ stats.tipAmount += amount;
50
+ stats.totalTips += 1;
51
+
52
+ CurrencyTransfer.transferCurrency(currency, sender, receiver, amount);
53
+ }
54
+
55
+ function totalTipsByCurrency(address currency) internal view returns (uint256) {
56
+ return layout().tippingStatsByCurrency[currency].totalTips;
57
+ }
58
+
59
+ function tipAmountByCurrency(address currency) internal view returns (uint256) {
60
+ return layout().tippingStatsByCurrency[currency].tipAmount;
61
+ }
62
+
63
+ function tipsByCurrencyByTokenId(
64
+ uint256 tokenId,
65
+ address currency
66
+ ) internal view returns (uint256) {
67
+ return layout().tipsByCurrencyByTokenId[tokenId][currency];
68
+ }
69
+
70
+ function tippingCurrencies() internal view returns (address[] memory) {
71
+ return layout().currencies.values();
72
+ }
73
+ }
@@ -0,0 +1,123 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {ITipping} from "./ITipping.sol";
6
+ import {ITownsPointsBase} from "src/airdrop/points/ITownsPoints.sol";
7
+ import {IPlatformRequirements} from "src/factory/facets/platform/requirements/IPlatformRequirements.sol";
8
+
9
+ // libraries
10
+ import {TippingBase} from "./TippingBase.sol";
11
+ import {MembershipStorage} from "src/spaces/facets/membership/MembershipStorage.sol";
12
+ import {BasisPoints} from "src/utils/libraries/BasisPoints.sol";
13
+ import {CurrencyTransfer} from "src/utils/libraries/CurrencyTransfer.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
+ import {ReentrancyGuard} from "solady/utils/ReentrancyGuard.sol";
19
+ import {ERC721ABase} from "src/diamond/facets/token/ERC721A/ERC721ABase.sol";
20
+ import {PointsBase} from "../points/PointsBase.sol";
21
+
22
+ contract TippingFacet is ITipping, ERC721ABase, PointsBase, Facet, ReentrancyGuard {
23
+ function __Tipping_init() external onlyInitializing {
24
+ _addInterface(type(ITipping).interfaceId);
25
+ }
26
+
27
+ /// @inheritdoc ITipping
28
+ function tip(TipRequest calldata tipRequest) external payable nonReentrant {
29
+ _validateTipRequest(
30
+ msg.sender,
31
+ tipRequest.receiver,
32
+ tipRequest.currency,
33
+ tipRequest.amount
34
+ );
35
+
36
+ uint256 tipAmount = tipRequest.amount;
37
+
38
+ if (tipRequest.currency == CurrencyTransfer.NATIVE_TOKEN) {
39
+ uint256 protocolFee = _payProtocol(msg.sender, tipRequest.amount);
40
+ tipAmount = tipRequest.amount - protocolFee;
41
+
42
+ address airdropDiamond = _getAirdropDiamond();
43
+ uint256 points = _getPoints(
44
+ airdropDiamond,
45
+ ITownsPointsBase.Action.Tip,
46
+ abi.encode(protocolFee)
47
+ );
48
+ _mintPoints(airdropDiamond, msg.sender, points);
49
+ }
50
+
51
+ TippingBase.tip(
52
+ msg.sender,
53
+ tipRequest.receiver,
54
+ tipRequest.tokenId,
55
+ tipRequest.currency,
56
+ tipAmount
57
+ );
58
+
59
+ emit Tip(
60
+ tipRequest.tokenId,
61
+ tipRequest.currency,
62
+ msg.sender,
63
+ tipRequest.receiver,
64
+ tipRequest.amount,
65
+ tipRequest.messageId,
66
+ tipRequest.channelId
67
+ );
68
+ }
69
+
70
+ /// @inheritdoc ITipping
71
+ function tippingCurrencies() external view returns (address[] memory) {
72
+ return TippingBase.tippingCurrencies();
73
+ }
74
+
75
+ /// @inheritdoc ITipping
76
+ function tipsByCurrencyAndTokenId(
77
+ uint256 tokenId,
78
+ address currency
79
+ ) external view returns (uint256) {
80
+ return TippingBase.tipsByCurrencyByTokenId(tokenId, currency);
81
+ }
82
+
83
+ /// @inheritdoc ITipping
84
+ function totalTipsByCurrency(address currency) external view returns (uint256) {
85
+ return TippingBase.totalTipsByCurrency(currency);
86
+ }
87
+
88
+ /// @inheritdoc ITipping
89
+ function tipAmountByCurrency(address currency) external view returns (uint256) {
90
+ return TippingBase.tipAmountByCurrency(currency);
91
+ }
92
+
93
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
94
+ /* Internal */
95
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
96
+
97
+ function _validateTipRequest(
98
+ address sender,
99
+ address receiver,
100
+ address currency,
101
+ uint256 amount
102
+ ) internal pure {
103
+ if (currency == address(0)) {
104
+ CustomRevert.revertWith(CurrencyIsZero.selector);
105
+ }
106
+ if (sender == receiver) CustomRevert.revertWith(CannotTipSelf.selector);
107
+ if (amount == 0) CustomRevert.revertWith(AmountIsZero.selector);
108
+ }
109
+
110
+ function _payProtocol(address sender, uint256 amount) internal returns (uint256 protocolFee) {
111
+ MembershipStorage.Layout storage ds = MembershipStorage.layout();
112
+ IPlatformRequirements platform = IPlatformRequirements(ds.spaceFactory);
113
+
114
+ protocolFee = BasisPoints.calculate(amount, 50); // 0.5%
115
+
116
+ CurrencyTransfer.transferCurrency(
117
+ CurrencyTransfer.NATIVE_TOKEN,
118
+ sender,
119
+ platform.getFeeRecipient(),
120
+ protocolFee
121
+ );
122
+ }
123
+ }
@@ -0,0 +1,64 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+
10
+ interface ITreasury {
11
+ /// @notice Withdraw funds from the treasury to a specified account
12
+ /// @dev Can only be called by the owner of the contract. Will revert if account is zero address
13
+ /// or if balance is 0
14
+ /// @param account The address to withdraw funds to
15
+ function withdraw(address account) external;
16
+
17
+ /// @notice Handle the receipt of a single ERC721 token
18
+ /// @dev Implements the IERC721Receiver interface to safely receive ERC721 tokens
19
+ /// @param operator The address which called `safeTransferFrom` function
20
+ /// @param from The address which previously owned the token
21
+ /// @param tokenId The NFT identifier which is being transferred
22
+ /// @param data Additional data with no specified format
23
+ /// @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
24
+ function onERC721Received(
25
+ address operator,
26
+ address from,
27
+ uint256 tokenId,
28
+ bytes calldata data
29
+ ) external returns (bytes4);
30
+
31
+ /// @notice Handle the receipt of a single ERC1155 token
32
+ /// @dev Implements the IERC1155Receiver interface to safely receive ERC1155 tokens
33
+ /// @param operator The address which called the `safeTransferFrom` function
34
+ /// @param from The address which previously owned the token
35
+ /// @param id The ID of the token being transferred
36
+ /// @param value The amount of tokens being transferred
37
+ /// @param data Additional data with no specified format
38
+ /// @return bytes4
39
+ /// `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
40
+ function onERC1155Received(
41
+ address operator,
42
+ address from,
43
+ uint256 id,
44
+ uint256 value,
45
+ bytes calldata data
46
+ ) external returns (bytes4);
47
+
48
+ /// @notice Handle the receipt of multiple ERC1155 tokens
49
+ /// @dev Implements the IERC1155Receiver interface to safely receive multiple ERC1155 tokens
50
+ /// @param operator The address which called the `safeBatchTransferFrom` function
51
+ /// @param from The address which previously owned the tokens
52
+ /// @param ids An array containing ids of each token being transferred
53
+ /// @param values An array containing amounts of each token being transferred
54
+ /// @param data Additional data with no specified format
55
+ /// @return bytes4
56
+ /// `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
57
+ function onERC1155BatchReceived(
58
+ address operator,
59
+ address from,
60
+ uint256[] calldata ids,
61
+ uint256[] calldata values,
62
+ bytes calldata data
63
+ ) external returns (bytes4);
64
+ }