Skip to content

Commit

Permalink
badge WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
sebsadface committed Oct 5, 2024
1 parent 6acb0db commit 2124337
Show file tree
Hide file tree
Showing 8 changed files with 1,087 additions and 0 deletions.
22 changes: 22 additions & 0 deletions contracts/interfaces/story-nft/IERC5192.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

/// @title Minimal Soulbound NFT Interface
/// @notice Minimal interface for soulbinding EIP-721 NFTs
interface IERC5192 {
/// @notice Emitted when the locking status is changed to locked.
/// @dev If a token is minted and the status is locked, this event should be emitted.
/// @param tokenId The identifier for a token.
event Locked(uint256 tokenId);

/// @notice Emitted when the locking status is changed to unlocked.
/// @dev If a token is minted and the status is unlocked, this event should be emitted.
/// @param tokenId The identifier for a token.
event Unlocked(uint256 tokenId);

/// @notice Returns the locking status of an Soulbound Token
/// @dev SBTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param tokenId The identifier for an SBT.
function locked(uint256 tokenId) external view returns (bool);
}
64 changes: 64 additions & 0 deletions contracts/interfaces/story-nft/IOrgNFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

/// @title Organization NFT Interface
/// @notice Each organization token represents a Story ecosystem project.
/// The root organization token represents Story.
/// Each organization token register as a IP on Story and is a derivative of the root organization IP.
interface IOrgNFT is IERC721Metadata {
////////////////////////////////////////////////////////////////////////////
// Errors //
////////////////////////////////////////////////////////////////////////////
/// @notice Caller is not the StoryNFTFactory contract.
/// @param caller The address of the caller.
/// @param storyNftFactory The address of the `StoryNFTFactory` contract.
error OrgNFT__CallerNotStoryNFTFactory(address caller, address storyNftFactory);

/// @notice Root organization NFT has not been minted yet (`mintRootOrgNft` has not been called).
error OrgNFT__RootOrgNftNotMinted();

/// @notice Zero address provided as a param to OrgNFT functions.
error OrgNFT__ZeroAddressParam();

////////////////////////////////////////////////////////////////////////////
// Events //
////////////////////////////////////////////////////////////////////////////
/// @notice Emitted when a organization token minted.
/// @param recipient The address of the recipient of the organization token.
/// @param orgNft The address of the organization NFT.
/// @param tokenId The ID of the minted organization token.
/// @param orgIpId The ID of the organization IP.
event OrgNFTMinted(address recipient, address orgNft, uint256 tokenId, address orgIpId);

////////////////////////////////////////////////////////////////////////////
// Functions //
////////////////////////////////////////////////////////////////////////////
/// @notice Mints the root organization token and register it as an IP.
/// @param recipient The address of the recipient of the root organization token.
/// @param tokenURI The URI of the root organization token.
/// @return rootOrgTokenId The ID of the root organization token.
/// @return rootOrgIpId The ID of the root organization IP.
function mintRootOrgNft(
address recipient,
string memory tokenURI
) external returns (uint256 rootOrgTokenId, address rootOrgIpId);

/// @notice Mints a organization token, register it as an IP,
/// and makes the IP as a derivative of the root organization IP.
/// @param recipient The address of the recipient of the minted organization token.
/// @param tokenURI The URI of the minted organization token.
/// @return orgTokenId The ID of the minted organization token.
/// @return orgIpId The ID of the organization IP.
function mintOrgNft(
address recipient,
string memory tokenURI
) external returns (uint256 orgTokenId, address orgIpId);

/// @notice Returns the ID of the root organization IP.
function getRootOrgIpId() external view returns (address);

/// @notice Returns the total supply of OrgNFT.
function totalSupply() external view returns (uint256);
}
79 changes: 79 additions & 0 deletions contracts/interfaces/story-nft/IStoryBadge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

import { IERC5192 } from "./IERC5192.sol";

/// @title Story Badge Interface
/// @notice A Story Badge is a soulbound NFT that has an unified token URI for all tokens.
interface IStoryBadge is IERC5192, IERC721Metadata {
////////////////////////////////////////////////////////////////////////////
// Errors //
////////////////////////////////////////////////////////////////////////////
/// @notice Invalid whitelist signature.
error StoryBadge__InvalidSignature();

/// @notice The provided whitelist signature is already used.
error StoryBadge__SignatureAlreadyUsed();

/// @notice Badges are soulbound, cannot be transferred.
error StoryBadge__TransferLocked();

/// @notice Zero address provided as a param to StoryBadge functions.
error StoryBadge__ZeroAddressParam();

////////////////////////////////////////////////////////////////////////////
// Structs //
////////////////////////////////////////////////////////////////////////////
/// @notice Struct for initializing the StoryBadge contract.
/// @param name The name of the collection.
/// @param symbol The symbol of the collection.
/// @param contractURI The contract URI of the collection (follows OpenSea contract-level metadata standard).
/// @param tokenURI The token URI for all the badges (follows OpenSea metadata standard).
/// @param signer The signer of the whitelist signatures.
struct InitParams {
string name;
string symbol;
string contractURI;
string tokenURI;
address signer;
}

////////////////////////////////////////////////////////////////////////////
// Events //
////////////////////////////////////////////////////////////////////////////
/// @notice Emitted when a badge is minted.
/// @param recipient The address of the recipient of the badge.
/// @param tokenId The token ID of the minted badge.
/// @param ipId The ID of the badge IP.
event StoryBadgeMinted(address recipient, uint256 tokenId, address ipId);

/// @notice Emitted when the signer is updated.
/// @param signer The new signer address.
event StoryBadgeSingerUpdated(address signer);

/// @notice Emitted when the token URI is updated.
/// @param tokenURI The new token URI.
event StoryBadgeTokenURIUpdated(string tokenURI);

////////////////////////////////////////////////////////////////////////////
// Functions //
////////////////////////////////////////////////////////////////////////////
/// @notice Mints a badge for the given recipient, registers it as an IP,
/// and makes it a derivative of the organization IP.
/// @param recipient The address of the recipient of the badge.
/// @param signature The signature from the whitelist signer. This signautre is genreated by having the whitelist
/// signer sign the caller's address (msg.sender) for this `mint` function.
/// @return tokenId The token ID of the minted badge.
/// @return ipId The ID of the badge IP.
function mint(address recipient, bytes calldata signature) external returns (uint256 tokenId, address ipId);

/// @notice Updates the whitelist signer.
/// @param signer_ The new whitelist signer address.
function setSigner(address signer_) external;

/// @notice Updates the unified token URI for all badges.
/// @param tokenURI_ The new token URI.
function setTokenURI(string memory tokenURI_) external;
}
114 changes: 114 additions & 0 deletions contracts/interfaces/story-nft/IStoryNFTFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

/// @title Story NFT Factory Interface
/// @notice Story NFT Factory is the entrypoint for creating new Story NFT collections.
interface IStoryNFTFactory {
////////////////////////////////////////////////////////////////////////////
// Errors //
////////////////////////////////////////////////////////////////////////////
/// @notice Invalid signature provided to StoryNFTFactory functions.
/// @param signature The signature that is invalid.
error StoryNFTFactory__InvalidSignature(bytes signature);

/// @notice NftTemplate is not whitelisted to be used as a StoryNFT.
/// @param nftTemplate The NFT template that is not whitelisted.
error StoryNFTFactory__NftTemplateNotWhitelisted(address nftTemplate);

/// @notice Organization is already deployed by the StoryNFTFactory.
/// @param orgName The name of the organization that is already deployed.
/// @param deployedStoryNft The address of the already deployed StoryNFT for the organization.
error StoryNFTFactory__OrgAlreadyDeployed(string orgName, address deployedStoryNft);

/// @notice Organization is not found in the StoryNFTFactory.
/// @param orgName The name of the organization that is not found.
error StoryNFTFactory__OrgNotFound(string orgName);

/// @notice Signature is already used to deploy a StoryNFT.
/// @param signature The signature that is already used.
error StoryNFTFactory__SignatureAlreadyUsed(bytes signature);

/// @notice BaseStoryNFT is not supported by the StoryNFTFactory.
/// @param tokenContract The address of the token contract that does not implement BaseStoryNFT.
error StoryNFTFactory__UnsupportedBaseStoryNFT(address tokenContract);

/// @notice Zero address provided as a param to StoryNFTFactory functions.
error StoryNFTFactory__ZeroAddressParam();

////////////////////////////////////////////////////////////////////////////
// Events //
////////////////////////////////////////////////////////////////////////////
/// @notice Emitted when a new orgnization NFT is minted and a new StoryNFT associated with it is deployed.
/// @param orgName The name of the organization.
/// @param orgNft The address of the organization NFT.
/// @param orgTokenId The token ID of the organization NFT.
/// @param orgIpId The ID of the organization IP.
/// @param storyNft The address of the deployed StoryNFT.
event StoryNftDeployed(string orgName, address orgNft, uint256 orgTokenId, address orgIpId, address storyNft);

/// @notice Emitted when the signer of the StoryNFTFactory is updated.
/// @param signer The new signer of the StoryNFTFactory.
event StoryNFTFactorySignerUpdated(address signer);

/// @notice Emitted when a new Story NFT template is whitelisted.
/// @param nftTemplate The new Story NFT template that is whitelisted to be used in StoryNFTFactory.
event StoryNFTFactoryNftTemplateWhitelisted(address nftTemplate);

////////////////////////////////////////////////////////////////////////////
// Functions //
////////////////////////////////////////////////////////////////////////////
/// @notice Mints a new organization NFT and deploys (creates a clone of) `storyNftTemplate` as the StoryNFT
/// associated with the new organization NFT.
/// @param storyNftTemplate The address of a whitelisted StoryNFT template to be cloned.
/// @param storyNftOwner The address of the owner of the new StoryNFT contract.
/// @param orgName The name of the organization.
/// @param orgTokenURI The token URI of the organization NFT.
/// @param signature The signature from the StoryNFTFactory's whitelist signer. This signautre is genreated by
/// having the whitelist signer sign the caller's address (msg.sender) for this `deployStoryNft` function.
/// @param initData The initialization data for the StoryNFT (see {IStoryBadge-InitParams} for an example).
/// @return orgTokenId The token ID of the organization NFT.
/// @return orgIpId The ID of the organization IP.
/// @return storyNft The address of the dployed StoryNFT
function deployStoryNft(
address storyNftTemplate,
address storyNftOwner,
string calldata orgName,
string calldata orgTokenURI,
bytes calldata signature,
bytes calldata initData
) external returns (uint256 orgTokenId, address orgIpId, address storyNft);

/// @notice Mints a new organization NFT and deploys (creates a clone of) `storyNftTemplate` as the StoryNFT
/// associated with the new organization NFT.
/// @dev Enforced to be only callable by the protocol admin in governance.
/// @param storyNftTemplate The address of a whitelisted StoryNFT template to be cloned.
/// @param storyNftOwner The address of the owner of the new StoryNFT contract.
/// @param orgName The name of the organization.
/// @param orgTokenURI The token URI of the organization NFT.
/// @param initData The initialization data for the StoryNFT (see {IStoryBadge-InitParams} for an example).
/// @return orgTokenId The token ID of the organization NFT.
/// @return orgIpId The ID of the organization IP.
/// @return storyNft The address of the dployed StoryNFT
function deployByAdmin(
address storyNftTemplate,
address storyNftOwner,
string calldata orgName,
string calldata orgTokenURI,
bytes calldata initData
) external returns (uint256 orgTokenId, address orgIpId, address storyNft);

/// @notice Sets the signer of the StoryNFTFactory.
/// @param signer The new signer of the StoryNFTFactory.
function setSigner(address signer) external;

/// @notice Whitelists a new StoryNFT template.
/// @param storyNftTemplate The new StoryNFT template to be whitelisted.
function whitelistNftTemplate(address storyNftTemplate) external;

/// @notice Returns the default StoryNFT template address.
function getDefaultStoryNftTemplate() external view returns (address);

/// @notice Returns the address of the StoryNFT for a given organization name.
/// @param orgName The name of the organization.
function getStoryNftAddress(string calldata orgName) external view returns (address);
}
Loading

0 comments on commit 2124337

Please sign in to comment.