@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,463 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IPlatformRequirements} from "../factory/facets/platform/requirements/IPlatformRequirements.sol";
6
+ import {IArchitect} from "../factory/facets/architect/IArchitect.sol";
7
+ import {ISwapFacet} from "../spaces/facets/swap/ISwapFacet.sol";
8
+ import {ISwapRouter} from "./ISwapRouter.sol";
9
+ import {ISignatureTransfer} from "@uniswap/permit2/src/interfaces/ISignatureTransfer.sol";
10
+
11
+ // libraries
12
+ import {BasisPoints} from "../utils/libraries/BasisPoints.sol";
13
+ import {CurrencyTransfer} from "../utils/libraries/CurrencyTransfer.sol";
14
+ import {CustomRevert} from "../utils/libraries/CustomRevert.sol";
15
+ import {Permit2Hash} from "./Permit2Hash.sol";
16
+ import {SwapRouterStorage} from "./SwapRouterStorage.sol";
17
+ import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
18
+ import {PermitHash} from "@uniswap/permit2/src/libraries/PermitHash.sol";
19
+ import {LibBit} from "solady/utils/LibBit.sol";
20
+ import {LibCall} from "solady/utils/LibCall.sol";
21
+ import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
22
+
23
+ // contracts
24
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
25
+ import {PausableBase} from "@towns-protocol/diamond/src/facets/pausable/PausableBase.sol";
26
+ import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
27
+
28
+ /**
29
+ * @title SwapRouter
30
+ * @notice Handles swaps through whitelisted routers with fee collection
31
+ * @dev This contract provides two swap execution methods:
32
+ *
33
+ * Standard Swaps (`executeSwap`):
34
+ * - User transfers tokens to contract, then swap executes
35
+ * - Supports both ERC20 tokens and native ETH
36
+ * - Traditional approve/transferFrom flow
37
+ *
38
+ * Permit2 Swaps (`executeSwapWithPermit`):
39
+ * - Enhanced security using Uniswap's Permit2 protocol with witness data
40
+ * - Direct token transfer: User → SwapRouter → DEX (skips intermediate approvals)
41
+ * - ERC20 tokens only (native ETH not supported)
42
+ * - Cryptographically binds permit signatures to exact swap parameters
43
+ * - Prevents front-running attacks through witness data binding
44
+ * - Uses EIP-712 witness containing ExactInputParams, RouterParams, and FeeConfig
45
+ * - Requires pre-approval of tokens to Permit2 contract
46
+ * - Provides nonce-based replay protection and deadline-based time bounds
47
+ */
48
+ contract SwapRouter is PausableBase, ReentrancyGuardTransient, ISwapRouter, Facet {
49
+ using CustomRevert for bytes4;
50
+ using SafeTransferLib for address;
51
+
52
+ /// @notice Universal Permit2 contract address
53
+ /// @dev This contract implements Uniswap's Permit2 protocol for signature-based token transfers
54
+ address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
55
+
56
+ /// @notice EIP-712 domain separator for Permit2
57
+ bytes32 internal immutable PERMIT2_DOMAIN_SEPARATOR =
58
+ ISignatureTransfer(PERMIT2).DOMAIN_SEPARATOR();
59
+
60
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
61
+ /* ADMIN FUNCTIONS */
62
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
63
+
64
+ /// @notice Initializes the SwapRouter with the space factory address
65
+ /// @param spaceFactory The address of the space factory
66
+ function __SwapRouter_init(address spaceFactory) external onlyInitializing {
67
+ SwapRouterStorage.layout().spaceFactory = spaceFactory;
68
+ emit SwapRouterInitialized(spaceFactory);
69
+ }
70
+
71
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
72
+ /* SWAP */
73
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
74
+
75
+ /// @inheritdoc ISwapRouter
76
+ /// @dev Handles refunds of unconsumed input tokens. For ERC20s, calculates actual received amount
77
+ /// to support fee-on-transfer tokens. For ETH, tracks original balance and refunds any unconsumed
78
+ /// ETH after the external router call. Refunds are sent back to msg.sender.
79
+ function executeSwap(
80
+ ExactInputParams calldata params,
81
+ RouterParams calldata routerParams,
82
+ address poster
83
+ ) external payable nonReentrant whenNotPaused returns (uint256 amountOut, uint256 protocolFee) {
84
+ // validate parameters before any transfers
85
+ _validateSwapParams(params, routerParams);
86
+
87
+ // for standard swaps, handle token transfer with balance check for fee-on-transfer tokens
88
+ uint256 tokenInBalanceBefore;
89
+
90
+ if (params.tokenIn != CurrencyTransfer.NATIVE_TOKEN) {
91
+ // ensure no ETH is sent when tokenIn is not native
92
+ if (msg.value != 0) SwapRouter__UnexpectedETH.selector.revertWith();
93
+
94
+ // use the actual received amount to handle fee-on-transfer tokens
95
+ tokenInBalanceBefore = params.tokenIn.balanceOf(address(this));
96
+ params.tokenIn.safeTransferFrom(msg.sender, address(this), params.amountIn);
97
+ } else {
98
+ // for native token, the value should be sent with the transaction
99
+ if (msg.value != params.amountIn) SwapRouter__InvalidAmount.selector.revertWith();
100
+
101
+ // store original balance before router call for ETH refunds
102
+ unchecked {
103
+ tokenInBalanceBefore = address(this).balance - msg.value;
104
+ }
105
+ }
106
+
107
+ return _executeSwap(params, routerParams, poster, tokenInBalanceBefore, msg.sender);
108
+ }
109
+
110
+ /// @inheritdoc ISwapRouter
111
+ /// @dev Uses Permit2 with witness data to bind permit signatures to exact swap parameters,
112
+ /// preventing front-running attacks. Requires user to pre-approve tokens to Permit2 contract.
113
+ /// Handles refunds of unconsumed ERC20 tokens back to the permit owner (not msg.sender).
114
+ function executeSwapWithPermit(
115
+ ExactInputParams calldata params,
116
+ RouterParams calldata routerParams,
117
+ FeeConfig calldata posterFee,
118
+ Permit2Params calldata permit
119
+ ) external payable nonReentrant whenNotPaused returns (uint256 amountOut, uint256 protocolFee) {
120
+ // validate parameters before any transfers
121
+ _validateSwapParams(params, routerParams);
122
+
123
+ // ensure no ETH is sent
124
+ if (msg.value != 0) SwapRouter__UnexpectedETH.selector.revertWith();
125
+
126
+ // Permit2 only works with ERC20 tokens, not native ETH
127
+ if (params.tokenIn == CurrencyTransfer.NATIVE_TOKEN) {
128
+ SwapRouter__NativeTokenNotSupportedWithPermit.selector.revertWith();
129
+ }
130
+
131
+ // validate that the poster fee in permit matches the actual configured fee
132
+ (, uint16 actualPosterBps) = _getSwapFees(_getSpaceFactory(), msg.sender);
133
+ if (actualPosterBps != posterFee.feeBps) {
134
+ SwapRouter__PosterFeeMismatch.selector.revertWith();
135
+ }
136
+
137
+ // take balance snapshot before Permit2 transfer to handle fee-on-transfer tokens
138
+ uint256 tokenInBalanceBefore = params.tokenIn.balanceOf(address(this));
139
+
140
+ // execute permit transfer from owner to this contract via Permit2
141
+ ISignatureTransfer(PERMIT2).permitWitnessTransferFrom(
142
+ ISignatureTransfer.PermitTransferFrom(
143
+ ISignatureTransfer.TokenPermissions(params.tokenIn, params.amountIn),
144
+ permit.nonce,
145
+ permit.deadline
146
+ ),
147
+ ISignatureTransfer.SignatureTransferDetails({
148
+ to: address(this),
149
+ requestedAmount: params.amountIn
150
+ }),
151
+ permit.owner, // owner who signed the permit
152
+ Permit2Hash.hash(SwapWitness(params, routerParams, posterFee)),
153
+ Permit2Hash.WITNESS_TYPE_STRING,
154
+ permit.signature
155
+ );
156
+
157
+ // execute the swap with the balance before transfer
158
+ return
159
+ _executeSwap(
160
+ params,
161
+ routerParams,
162
+ posterFee.recipient,
163
+ tokenInBalanceBefore,
164
+ permit.owner
165
+ );
166
+ }
167
+
168
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
169
+ /* GETTERS */
170
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
171
+
172
+ /// @inheritdoc ISwapRouter
173
+ function getETHInputFees(
174
+ uint256 amountIn,
175
+ address caller,
176
+ address poster
177
+ ) external view returns (uint256 amountInAfterFees, uint256 protocolFee, uint256 posterFee) {
178
+ address spaceFactory = _getSpaceFactory();
179
+
180
+ // get fee rates based on whether the caller is a space
181
+ (uint16 protocolBps, uint16 posterBps) = _getSwapFees(spaceFactory, caller);
182
+
183
+ // calculate fees and amount after fees
184
+ return _calculateSwapFees(amountIn, protocolBps, posterBps, poster);
185
+ }
186
+
187
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
188
+ /* PERMIT2 UTILS */
189
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
190
+
191
+ /// @inheritdoc ISwapRouter
192
+ function getPermit2Nonce(
193
+ address owner,
194
+ uint256 startNonce
195
+ ) external view returns (uint256 nonce) {
196
+ unchecked {
197
+ uint256 bitPos = startNonce & 0xff;
198
+
199
+ for (uint256 wordPos = startNonce >> 8; wordPos <= type(uint248).max; ++wordPos) {
200
+ uint256 bitmap = ISignatureTransfer(PERMIT2).nonceBitmap(owner, uint248(wordPos));
201
+
202
+ // create mask to ignore bits below bitPos (set bits below bitPos to 1)
203
+ uint256 mask = (1 << bitPos) - 1;
204
+ uint256 availableBits = ~(bitmap | mask);
205
+
206
+ // if there are available bits in this word, find the first one
207
+ if (availableBits != 0) {
208
+ // find first set bit in availableBits (which represents available nonces)
209
+ uint256 firstZeroBit = LibBit.ffs(availableBits);
210
+ return (wordPos << 8) | firstZeroBit;
211
+ }
212
+
213
+ bitPos = 0; // reset for next word
214
+ }
215
+
216
+ // no available nonces found
217
+ return type(uint256).max;
218
+ }
219
+ }
220
+
221
+ /// @inheritdoc ISwapRouter
222
+ function getPermit2MessageHash(
223
+ ExactInputParams calldata params,
224
+ RouterParams calldata routerParams,
225
+ FeeConfig calldata posterFee,
226
+ uint256 amount,
227
+ uint256 nonce,
228
+ uint256 deadline
229
+ ) external view returns (bytes32 messageHash) {
230
+ bytes32 witnessHash = Permit2Hash.hash(SwapWitness(params, routerParams, posterFee));
231
+ bytes32 tokenPermissions = keccak256(
232
+ abi.encode(PermitHash._TOKEN_PERMISSIONS_TYPEHASH, params.tokenIn, amount)
233
+ );
234
+
235
+ bytes32 structHash = keccak256(
236
+ abi.encode(
237
+ Permit2Hash.PERMIT_WITNESS_TRANSFER_FROM_TYPEHASH,
238
+ tokenPermissions,
239
+ address(this), // spender
240
+ nonce,
241
+ deadline,
242
+ witnessHash
243
+ )
244
+ );
245
+
246
+ return MessageHashUtils.toTypedDataHash(PERMIT2_DOMAIN_SEPARATOR, structHash);
247
+ }
248
+
249
+ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
250
+ /* INTERNAL */
251
+ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
252
+
253
+ /// @notice Validates swap parameters before any transfers occur
254
+ /// @param params The parameters for the swap
255
+ /// @param routerParams The router parameters for the swap
256
+ function _validateSwapParams(
257
+ ExactInputParams calldata params,
258
+ RouterParams calldata routerParams
259
+ ) internal view {
260
+ // require explicit recipient
261
+ if (params.recipient == address(0)) SwapRouter__RecipientRequired.selector.revertWith();
262
+
263
+ // prevent swaps where tokenIn and tokenOut are the same
264
+ if (params.tokenIn == params.tokenOut) SwapRouter__SameToken.selector.revertWith();
265
+
266
+ // only allow whitelisted routers
267
+ if (!_isRouterWhitelisted(routerParams.router)) {
268
+ SwapRouter__InvalidRouter.selector.revertWith();
269
+ }
270
+ if (!_isRouterWhitelisted(routerParams.approveTarget)) {
271
+ SwapRouter__InvalidRouter.selector.revertWith();
272
+ }
273
+ }
274
+
275
+ /// @notice Internal function to execute a swap with tokens already in the contract
276
+ /// @param params The parameters for the swap
277
+ /// @param routerParams The router parameters for the swap
278
+ /// @param poster The address that posted this swap opportunity
279
+ /// @param tokenInBalanceBefore The balance of input token before any transfers (0 for ETH)
280
+ /// @param payer The address that should receive any refund of unconsumed input tokens
281
+ /// @return amountOut The amount of tokenOut received
282
+ /// @return protocolFee The protocol fee amount
283
+ function _executeSwap(
284
+ ExactInputParams calldata params,
285
+ RouterParams calldata routerParams,
286
+ address poster,
287
+ uint256 tokenInBalanceBefore,
288
+ address payer
289
+ ) internal returns (uint256 amountOut, uint256 protocolFee) {
290
+ // snapshot the balance of tokenOut before the swap
291
+ uint256 balanceBefore = _getBalance(params.tokenOut);
292
+
293
+ bool isNativeToken = params.tokenIn == CurrencyTransfer.NATIVE_TOKEN;
294
+ {
295
+ uint256 value;
296
+
297
+ if (!isNativeToken) {
298
+ // calculate actualAmountIn for ERC20
299
+ uint256 actualAmountIn = params.tokenIn.balanceOf(address(this)) -
300
+ tokenInBalanceBefore;
301
+
302
+ // tokens are already in the contract, just approve the router
303
+ params.tokenIn.safeApprove(routerParams.approveTarget, actualAmountIn);
304
+ } else {
305
+ // calculate and collect fees before the swap for ETH input
306
+ (value, protocolFee, ) = _collectFees(
307
+ CurrencyTransfer.NATIVE_TOKEN,
308
+ msg.value,
309
+ poster
310
+ );
311
+ }
312
+
313
+ // execute swap with the router
314
+ LibCall.callContract(routerParams.router, value, routerParams.swapData);
315
+
316
+ // reset approval for tokenIn
317
+ if (!isNativeToken) params.tokenIn.safeApprove(routerParams.approveTarget, 0);
318
+
319
+ // refund any unconsumed input tokens to the payer
320
+ uint256 refundAmount = _getBalance(params.tokenIn) - tokenInBalanceBefore;
321
+ CurrencyTransfer.transferCurrency(params.tokenIn, address(this), payer, refundAmount);
322
+ }
323
+
324
+ // use the actual received amount to handle fee-on-transfer tokens
325
+ amountOut = _getBalance(params.tokenOut) - balanceBefore;
326
+
327
+ // calculate and distribute fees only for non-ETH inputs
328
+ // for ETH inputs, fees were already collected before the swap
329
+ if (!isNativeToken) {
330
+ (amountOut, protocolFee, ) = _collectFees(params.tokenOut, amountOut, poster);
331
+ }
332
+
333
+ // slippage check after fees
334
+ if (amountOut < params.minAmountOut) SwapRouter__InsufficientOutput.selector.revertWith();
335
+
336
+ // transfer remaining tokens to the recipient
337
+ CurrencyTransfer.transferCurrency(
338
+ params.tokenOut,
339
+ address(this),
340
+ params.recipient,
341
+ amountOut
342
+ );
343
+
344
+ emit Swap(
345
+ routerParams.router,
346
+ msg.sender,
347
+ params.tokenIn,
348
+ params.tokenOut,
349
+ params.amountIn,
350
+ amountOut,
351
+ params.recipient
352
+ );
353
+ }
354
+
355
+ /// @notice Collects and distributes both protocol and poster fees
356
+ /// @param token The token to collect fees in
357
+ /// @param amount The amount to calculate fees from
358
+ /// @param poster The address that posted this swap opportunity
359
+ /// @return amountAfterFees The amount after deducting protocol and poster fees
360
+ /// @return protocolFee The protocol fee amount collected
361
+ /// @return posterFee The poster fee amount collected
362
+ function _collectFees(
363
+ address token,
364
+ uint256 amount,
365
+ address poster
366
+ ) internal returns (uint256 amountAfterFees, uint256 protocolFee, uint256 posterFee) {
367
+ address spaceFactory = _getSpaceFactory();
368
+ (uint16 protocolBps, uint16 posterBps) = _getSwapFees(spaceFactory, msg.sender);
369
+
370
+ // calculate fees
371
+ (amountAfterFees, protocolFee, posterFee) = _calculateSwapFees(
372
+ amount,
373
+ protocolBps,
374
+ posterBps,
375
+ poster
376
+ );
377
+
378
+ // transfer fees
379
+ address feeRecipient = IPlatformRequirements(spaceFactory).getFeeRecipient();
380
+ CurrencyTransfer.transferCurrency(token, address(this), feeRecipient, protocolFee);
381
+
382
+ if (posterFee > 0) {
383
+ CurrencyTransfer.transferCurrency(token, address(this), poster, posterFee);
384
+ }
385
+
386
+ emit FeeDistribution(token, feeRecipient, poster, protocolFee, posterFee);
387
+ }
388
+
389
+ function _getSwapFees(
390
+ address spaceFactory,
391
+ address caller
392
+ ) internal view returns (uint16 protocolBps, uint16 posterBps) {
393
+ // check if caller is a space
394
+ bool isSpace = IArchitect(spaceFactory).getTokenIdBySpace(caller) != 0;
395
+
396
+ // get fee configuration based on whether caller is a space
397
+ if (isSpace) {
398
+ try ISwapFacet(caller).getSwapFees() returns (
399
+ uint16 spaceTreasuryBps,
400
+ uint16 spacePosterBps,
401
+ bool
402
+ ) {
403
+ return (spaceTreasuryBps, spacePosterBps);
404
+ } catch {}
405
+ // fallback to platform fees if the space doesn't implement getSwapFees
406
+ }
407
+ IPlatformRequirements platform = IPlatformRequirements(spaceFactory);
408
+ return platform.getSwapFees();
409
+ }
410
+
411
+ function _getSpaceFactory() internal view returns (address) {
412
+ return SwapRouterStorage.layout().spaceFactory;
413
+ }
414
+
415
+ function _getPlatformRequirements() internal view returns (IPlatformRequirements) {
416
+ return IPlatformRequirements(_getSpaceFactory());
417
+ }
418
+
419
+ /// @notice Checks if a router is whitelisted
420
+ /// @param router The address to check
421
+ /// @return bool True if the router is whitelisted
422
+ function _isRouterWhitelisted(address router) internal view returns (bool) {
423
+ return _getPlatformRequirements().isRouterWhitelisted(router);
424
+ }
425
+
426
+ /// @notice Gets the balance of a token for this contract
427
+ /// @param token The token to check
428
+ /// @return uint256 The balance
429
+ function _getBalance(address token) internal view returns (uint256) {
430
+ if (token != CurrencyTransfer.NATIVE_TOKEN) return token.balanceOf(address(this));
431
+ return address(this).balance;
432
+ }
433
+
434
+ /// @notice Calculates swap fees and the amount after fees
435
+ /// @param amount The original amount to calculate fees from
436
+ /// @param protocolBps Protocol fee in basis points
437
+ /// @param posterBps Poster fee in basis points
438
+ /// @param poster The address that posted this swap opportunity
439
+ /// @return amountAfterFees The amount after deducting protocol and poster fees
440
+ /// @return protocolFee The protocol fee amount computed
441
+ /// @return posterFee The poster fee amount computed
442
+ function _calculateSwapFees(
443
+ uint256 amount,
444
+ uint16 protocolBps,
445
+ uint16 posterBps,
446
+ address poster
447
+ ) internal pure returns (uint256 amountAfterFees, uint256 protocolFee, uint256 posterFee) {
448
+ if (protocolBps + posterBps > BasisPoints.MAX_BPS) {
449
+ SwapRouter__InvalidBps.selector.revertWith();
450
+ }
451
+
452
+ // calculate protocol fee
453
+ protocolFee = BasisPoints.calculate(amount, protocolBps);
454
+
455
+ // only calculate poster fee if the address is not zero
456
+ if (poster != address(0)) posterFee = BasisPoints.calculate(amount, posterBps);
457
+
458
+ // calculate amount after fees
459
+ unchecked {
460
+ amountAfterFees = amount - protocolFee - posterFee;
461
+ }
462
+ }
463
+ }
@@ -0,0 +1,21 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ /// @title SwapRouterStorage
5
+ /// @notice Storage layout for the SwapRouter contract
6
+ library SwapRouterStorage {
7
+ // keccak256(abi.encode(uint256(keccak256("router.swap.storage")) - 1)) &
8
+ // ~bytes32(uint256(0xff))
9
+ bytes32 internal constant STORAGE_SLOT =
10
+ 0xbaabbaf01fc4f6195bfdcefdfc41afc4577058a099d6e5a21edcf605dd045400;
11
+
12
+ struct Layout {
13
+ address spaceFactory;
14
+ }
15
+
16
+ function layout() internal pure returns (Layout storage l) {
17
+ assembly {
18
+ l.slot := STORAGE_SLOT
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+ interface ICrossChainEntitlement {
10
+ struct Parameter {
11
+ string name;
12
+ string primitive;
13
+ string description;
14
+ }
15
+
16
+ function isEntitled(
17
+ address[] calldata users,
18
+ bytes calldata parameters
19
+ ) external view returns (bool);
20
+
21
+ function parameters() external view returns (Parameter[] memory);
22
+ }
@@ -0,0 +1,61 @@
1
+ //SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ interface IEntitlementBase {
5
+ // Caller is not allowed to perform this action
6
+ error Entitlement__NotAllowed();
7
+
8
+ // Caller has passed an invalid value
9
+ error Entitlement__InvalidValue();
10
+
11
+ // Caller has passed a value that already exists
12
+ error Entitlement__ValueAlreadyExists();
13
+
14
+ // Caller is not a member
15
+ error Entitlement__NotMember();
16
+ }
17
+
18
+ interface IEntitlement is IEntitlementBase {
19
+ /// @notice initializes the entitlement module
20
+ function initialize(address space) external;
21
+
22
+ /// @notice The name of the entitlement module
23
+ function name() external view returns (string memory);
24
+
25
+ /// @notice The type of the entitlement module
26
+ function moduleType() external view returns (string memory);
27
+
28
+ /// @notice The description of the entitlement module
29
+ function description() external view returns (string memory);
30
+
31
+ /// @notice sets a new entitlement
32
+ /// @param roleId id of the role to gate
33
+ /// @param entitlementData abi encoded array of data necessary to set the entitlement
34
+ function setEntitlement(uint256 roleId, bytes calldata entitlementData) external;
35
+
36
+ /// @notice removes an entitlement
37
+ /// @param roleId id of the role to remove
38
+ function removeEntitlement(uint256 roleId) external;
39
+
40
+ /// @notice fetches the entitlement data for a roleId
41
+ /// @param roleId the roleId to fetch the entitlement data for
42
+ /// @return entitlementData array for the role
43
+ function getEntitlementDataByRoleId(uint256 roleId) external view returns (bytes memory);
44
+
45
+ /// @notice some entitlements require cross chain evaluation and may not be executed directly
46
+ /// from
47
+ /// other contracts
48
+ /// @return whether this entitlement will require crosschain evaluation
49
+ function isCrosschain() external view returns (bool);
50
+
51
+ /// @notice checks whether a user is has a given permission for a channel or a space
52
+ /// @param channelId id of the channel to check, if empty, checks space
53
+ /// @param user address of the user to check
54
+ /// @param permission the permission to check
55
+ /// @return whether the user is entitled to the permission
56
+ function isEntitled(
57
+ bytes32 channelId,
58
+ address[] memory user,
59
+ bytes32 permission
60
+ ) external view returns (bool);
61
+ }
@@ -0,0 +1,79 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
5
+ import {ICrossChainEntitlement} from "src/spaces/entitlements/ICrossChainEntitlement.sol";
6
+
7
+ interface IGnosisSafeProxyFactory {
8
+ function computeProxyAddress(address user) external view returns (address);
9
+ }
10
+
11
+ contract PolymarketEntitlement is ICrossChainEntitlement {
12
+ IGnosisSafeProxyFactory public proxyFactory;
13
+ IERC1155 public tokenContract;
14
+
15
+ constructor() {
16
+ // Set the proxyFactory and token contract addresses
17
+ proxyFactory = IGnosisSafeProxyFactory(address(0xaacFeEa03eb1561C4e67d661e40682Bd20E3541b));
18
+ tokenContract = IERC1155(address(0x4D97DCd97eC945f40cF65F87097ACe5EA0476045));
19
+ }
20
+
21
+ function isEntitled(
22
+ address[] calldata users,
23
+ bytes calldata paramData
24
+ ) external view override returns (bool) {
25
+ (uint256 tokenId, uint256 requiredBalance, bool aggregate) = abi.decode(
26
+ paramData,
27
+ (uint256, uint256, bool)
28
+ );
29
+
30
+ uint256 totalBalance = 0;
31
+
32
+ for (uint256 i = 0; i < users.length; i++) {
33
+ address userAddress = users[i];
34
+ address proxyAddress = proxyFactory.computeProxyAddress(userAddress);
35
+
36
+ // Check balance for both the user and the proxy
37
+ uint256 userBalance = tokenContract.balanceOf(userAddress, tokenId);
38
+ uint256 proxyBalance = tokenContract.balanceOf(proxyAddress, tokenId);
39
+
40
+ if (aggregate) {
41
+ // Add both user and proxy balance to the total
42
+ totalBalance += userBalance + proxyBalance;
43
+ } else {
44
+ // If not aggregating, return true if any address meets the threshold
45
+ if (userBalance >= requiredBalance || proxyBalance >= requiredBalance) {
46
+ return true;
47
+ }
48
+ }
49
+ }
50
+
51
+ // If aggregating, check if the total balance meets the threshold
52
+ if (aggregate) {
53
+ return totalBalance >= requiredBalance;
54
+ }
55
+
56
+ // If not aggregating, and no address met the threshold, return false
57
+ return false;
58
+ }
59
+
60
+ function parameters() external pure override returns (Parameter[] memory) {
61
+ Parameter[] memory params = new Parameter[](3);
62
+ params[0] = Parameter({
63
+ name: "tokenId",
64
+ primitive: "uint256",
65
+ description: "The token ID of the ERC-1155 token."
66
+ });
67
+ params[1] = Parameter({
68
+ name: "requiredBalance",
69
+ primitive: "uint256",
70
+ description: "The minimum balance required for entitlement."
71
+ });
72
+ params[2] = Parameter({
73
+ name: "aggregate",
74
+ primitive: "bool",
75
+ description: "Whether to aggregate balances across all wallets."
76
+ });
77
+ return params;
78
+ }
79
+ }
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+
10
+ interface IPOAP {
11
+ /// @notice Get the POAP token balance of an owner
12
+ /// @param owner The address to query the balance of
13
+ /// @return The number of POAP tokens owned by the given address
14
+ function balanceOf(address owner) external view returns (uint256);
15
+
16
+ /// @dev Gets the Token Id and Event Id for a given index of the tokens list of the requested
17
+ /// owner
18
+ /// @param owner ( address ) Owner address of the token list to be queried
19
+ /// @param index ( uint256 ) Index to be accessed of the requested tokens list
20
+ /// @return tokenId The unique identifier of the POAP token
21
+ /// @return eventId The ID of the event associated with the POAP token
22
+ function tokenDetailsOfOwnerByIndex(
23
+ address owner,
24
+ uint256 index
25
+ ) external view returns (uint256 tokenId, uint256 eventId);
26
+ }