diff --git a/src/spaces/Space.sol b/src/spaces/Space.sol new file mode 100644 index 0000000..58c3dc1 --- /dev/null +++ b/src/spaces/Space.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./interfaces/ISpace.sol"; +import "../stamps/interfaces/IFollowerSinceStamp.sol"; +import "../points/interfaces/IFollowerSincePoints.sol"; +import "../voting/interfaces/IQuestion.sol"; +import "../voting/FixedQuestion.sol"; +import "../voting/OpenQuestion.sol"; +import "../stamps/FollowerSinceStamp.sol"; +import "../points/FollowerSincePoints.sol"; + +/// @title Space +/// @notice Represents a space, organization, or leader using Plasa for their community +/// @dev This contract manages follower stamps, points, and questions for a community +contract Space is ISpace, Ownable { + IFollowerSinceStamp public followerStamp; + IFollowerSincePoints public followerPoints; + IQuestion[] private questions; + + /// @notice Initializes the PoCSpace contract + /// @param initialOwner The address that will own this space + /// @param stampSigner The address authorized to sign mint requests for follower stamps + /// @param platform The platform name (e.g., "Instagram", "Twitter") + /// @param followed The account being followed + /// @param spaceName The name of the space + constructor( + address initialOwner, + address stampSigner, + string memory platform, + string memory followed, + string memory spaceName + ) Ownable(initialOwner) { + // Deploy FollowerSinceStamp contract + followerStamp = IFollowerSinceStamp( + address(new FollowerSinceStamp(stampSigner, platform, followed)) + ); + emit FollowerStampDeployed(address(followerStamp)); + + // Deploy FollowerSincePoints contract + string memory pointsName = string(abi.encodePacked(spaceName, " Points")); + followerPoints = IFollowerSincePoints( + address(new FollowerSincePoints(address(followerStamp), pointsName, "FP")) + ); + emit FollowerPointsDeployed(address(followerPoints)); + } + + /// @inheritdoc ISpace + function deployFixedQuestion( + string memory title, + string memory description, + uint256 deadline, + string[] memory initialOptionTitles, + string[] memory initialOptionDescriptions + ) external onlyOwner returns (address) { + FixedQuestion newQuestion = new FixedQuestion( + owner(), + title, + description, + deadline, + address(followerPoints), + initialOptionTitles, + initialOptionDescriptions + ); + questions.push(IQuestion(address(newQuestion))); + emit QuestionDeployed(address(newQuestion), IQuestion.QuestionType.Fixed); + return address(newQuestion); + } + + /// @inheritdoc ISpace + function deployOpenQuestion( + string memory title, + string memory description, + uint256 deadline, + uint256 minPointsToAddOption + ) external onlyOwner returns (address) { + OpenQuestion newQuestion = new OpenQuestion( + owner(), + title, + description, + deadline, + address(followerPoints), + minPointsToAddOption + ); + questions.push(IQuestion(address(newQuestion))); + emit QuestionDeployed(address(newQuestion), IQuestion.QuestionType.Open); + return address(newQuestion); + } + + /// @inheritdoc ISpace + function getQuestions() external view returns (IQuestion[] memory) { + return questions; + } + + /// @inheritdoc ISpace + function getQuestionCount() external view returns (uint256) { + return questions.length; + } +} diff --git a/src/spaces/interfaces/ISpace.sol b/src/spaces/interfaces/ISpace.sol new file mode 100644 index 0000000..6ab0941 --- /dev/null +++ b/src/spaces/interfaces/ISpace.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "../../stamps/interfaces/IFollowerSinceStamp.sol"; +import "../../points/interfaces/IFollowerSincePoints.sol"; +import "../../voting/interfaces/IQuestion.sol"; + +/// @title ISpace +/// @notice Interface for the Space contract, representing a community or organization using Plasa +/// @dev This interface defines the structure for managing follower stamps, points, and questions +interface ISpace { + // Public variables + /// @notice Returns the FollowerSinceStamp contract associated with this space + /// @return The IFollowerSinceStamp interface of the associated stamp contract + function followerStamp() external view returns (IFollowerSinceStamp); + + /// @notice Returns the FollowerSincePoints contract associated with this space + /// @return The IFollowerSincePoints interface of the associated points contract + function followerPoints() external view returns (IFollowerSincePoints); + + // Events + /// @notice Emitted when a new FollowerSinceStamp contract is deployed + /// @param stampAddress The address of the newly deployed FollowerSinceStamp contract + event FollowerStampDeployed(address stampAddress); + + /// @notice Emitted when a new FollowerSincePoints contract is deployed + /// @param pointsAddress The address of the newly deployed FollowerSincePoints contract + event FollowerPointsDeployed(address pointsAddress); + + /// @notice Emitted when a new question contract is deployed + /// @param questionAddress The address of the newly deployed question contract + /// @param questionType The type of the question (Fixed or Open) + event QuestionDeployed(address questionAddress, IQuestion.QuestionType questionType); + + // Public functions + /// @notice Deploys a new fixed question + /// @dev Only the owner can call this function + /// @param title The title of the question + /// @param description The description of the question + /// @param deadline The deadline for voting + /// @param initialOptionTitles The titles of the initial options + /// @param initialOptionDescriptions The descriptions of the initial options + /// @return The address of the newly deployed question contract + function deployFixedQuestion( + string memory title, + string memory description, + uint256 deadline, + string[] memory initialOptionTitles, + string[] memory initialOptionDescriptions + ) external returns (address); + + /// @notice Deploys a new open question + /// @dev Only the owner can call this function + /// @param title The title of the question + /// @param description The description of the question + /// @param deadline The deadline for voting + /// @param minPointsToAddOption The minimum points required to add an option + /// @return The address of the newly deployed question contract + function deployOpenQuestion( + string memory title, + string memory description, + uint256 deadline, + uint256 minPointsToAddOption + ) external returns (address); + + /// @notice Gets all deployed questions + /// @return An array of IQuestion interfaces representing all deployed questions + function getQuestions() external view returns (IQuestion[] memory); + + /// @notice Gets the total number of deployed questions + /// @return The number of deployed questions + function getQuestionCount() external view returns (uint256); +}