Skip to content

Commit b2cb854

Browse files
committed
badge WIP
1 parent 6acb0db commit b2cb854

File tree

8 files changed

+1071
-0
lines changed

8 files changed

+1071
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.26;
3+
4+
/// @title Minimal Soulbound NFT Interface
5+
/// @notice Minimal interface for soulbinding EIP-721 NFTs
6+
interface IERC5192 {
7+
/// @notice Emitted when the locking status is changed to locked.
8+
/// @dev If a token is minted and the status is locked, this event should be emitted.
9+
/// @param tokenId The identifier for a token.
10+
event Locked(uint256 tokenId);
11+
12+
/// @notice Emitted when the locking status is changed to unlocked.
13+
/// @dev If a token is minted and the status is unlocked, this event should be emitted.
14+
/// @param tokenId The identifier for a token.
15+
event Unlocked(uint256 tokenId);
16+
17+
/// @notice Returns the locking status of an Soulbound Token
18+
/// @dev SBTs assigned to zero address are considered invalid, and queries
19+
/// about them do throw.
20+
/// @param tokenId The identifier for an SBT.
21+
function locked(uint256 tokenId) external view returns (bool);
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.26;
3+
4+
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
5+
6+
/// @title Organization NFT Interface
7+
/// @notice Each organization token represents a Story ecosystem project.
8+
/// The root organization token represents Story.
9+
/// Each organization token register as a IP on Story and is a derivative of the root organization IP.
10+
interface IOrgNFT is IERC721Metadata {
11+
////////////////////////////////////////////////////////////////////////////
12+
// Errors //
13+
////////////////////////////////////////////////////////////////////////////
14+
/// @notice Caller is not the StoryNFTFactory contract.
15+
/// @param caller The address of the caller.
16+
/// @param storyNftFactory The address of the `StoryNFTFactory` contract.
17+
error OrgNFT__CallerNotStoryNFTFactory(address caller, address storyNftFactory);
18+
19+
/// @notice Root organization NFT has not been minted yet (`mintRootOrgNft` has not been called).
20+
error OrgNFT__RootOrgNftNotMinted();
21+
22+
/// @notice Zero address provided as a param to OrgNFT functions.
23+
error OrgNFT__ZeroAddressParam();
24+
25+
////////////////////////////////////////////////////////////////////////////
26+
// Events //
27+
////////////////////////////////////////////////////////////////////////////
28+
/// @notice Emitted when a organization token minted.
29+
/// @param recipient The address of the recipient of the organization token.
30+
/// @param orgNft The address of the organization NFT.
31+
/// @param tokenId The ID of the minted organization token.
32+
/// @param orgIpId The ID of the organization IP.
33+
event OrgNFTMinted(address recipient, address orgNft, uint256 tokenId, address orgIpId);
34+
35+
////////////////////////////////////////////////////////////////////////////
36+
// Functions //
37+
////////////////////////////////////////////////////////////////////////////
38+
/// @notice Mints the root organization token and register it as an IP.
39+
/// @param recipient The address of the recipient of the root organization token.
40+
/// @param tokenURI The URI of the root organization token.
41+
/// @return rootOrgTokenId The ID of the root organization token.
42+
/// @return rootOrgIpId The ID of the root organization IP.
43+
function mintRootOrgNft(
44+
address recipient,
45+
string memory tokenURI
46+
) external returns (uint256 rootOrgTokenId, address rootOrgIpId);
47+
48+
/// @notice Mints a organization token, register it as an IP,
49+
/// and makes the IP as a derivative of the root organization IP.
50+
/// @param recipient The address of the recipient of the minted organization token.
51+
/// @param tokenURI The URI of the minted organization token.
52+
/// @return orgTokenId The ID of the minted organization token.
53+
/// @return orgIpId The ID of the organization IP.
54+
function mintOrgNft(
55+
address recipient,
56+
string memory tokenURI
57+
) external returns (uint256 orgTokenId, address orgIpId);
58+
59+
/// @notice Returns the ID of the root organization IP.
60+
function getRootOrgIpId() external view returns (address);
61+
62+
/// @notice Returns the total supply of OrgNFT.
63+
function totalSupply() external view returns (uint256);
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.26;
3+
4+
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
5+
6+
import { IERC5192 } from "./IERC5192.sol";
7+
8+
/// @title Story Badge Interface
9+
/// @notice A Story Badge is a soulbound NFT that has an unified token URI for all tokens.
10+
interface IStoryBadge is IERC5192, IERC721Metadata {
11+
////////////////////////////////////////////////////////////////////////////
12+
// Errors //
13+
////////////////////////////////////////////////////////////////////////////
14+
/// @notice Invalid whitelist signature.
15+
error StoryBadge__InvalidSignature();
16+
17+
/// @notice The provided whitelist signature is already used.
18+
error StoryBadge__SignatureAlreadyUsed();
19+
20+
/// @notice Badges are soulbound, cannot be transferred.
21+
error StoryBadge__TransferLocked();
22+
23+
/// @notice Zero address provided as a param to StoryBadge functions.
24+
error StoryBadge__ZeroAddressParam();
25+
26+
////////////////////////////////////////////////////////////////////////////
27+
// Structs //
28+
////////////////////////////////////////////////////////////////////////////
29+
/// @notice Struct for initializing the StoryBadge contract.
30+
/// @param name The name of the collection.
31+
/// @param symbol The symbol of the collection.
32+
/// @param contractURI The contract URI of the collection (follows OpenSea contract-level metadata standard).
33+
/// @param tokenURI The token URI for all the badges (follows OpenSea metadata standard).
34+
/// @param signer The signer of the whitelist signatures.
35+
struct InitParams {
36+
string name;
37+
string symbol;
38+
string contractURI;
39+
string tokenURI;
40+
address signer;
41+
}
42+
43+
////////////////////////////////////////////////////////////////////////////
44+
// Events //
45+
////////////////////////////////////////////////////////////////////////////
46+
/// @notice Emitted when a badge is minted.
47+
/// @param recipient The address of the recipient of the badge.
48+
/// @param tokenId The token ID of the minted badge.
49+
/// @param ipId The ID of the badge IP.
50+
event StoryBadgeMinted(address recipient, uint256 tokenId, address ipId);
51+
52+
/// @notice Emitted when the signer is updated.
53+
/// @param signer The new signer address.
54+
event StoryBadgeSingerUpdated(address signer);
55+
56+
/// @notice Emitted when the token URI is updated.
57+
/// @param tokenURI The new token URI.
58+
event StoryBadgeTokenURIUpdated(string tokenURI);
59+
60+
////////////////////////////////////////////////////////////////////////////
61+
// Functions //
62+
////////////////////////////////////////////////////////////////////////////
63+
/// @notice Mints a badge for the given recipient, registers it as an IP,
64+
/// and makes it a derivative of the organization IP.
65+
/// @param recipient The address of the recipient of the badge.
66+
/// @param signature The signature from the whitelist signer. This signautre is genreated by having the whitelist
67+
/// signer sign the caller's address (msg.sender) for this `mint` function.
68+
/// @return tokenId The token ID of the minted badge.
69+
/// @return ipId The ID of the badge IP.
70+
function mint(address recipient, bytes calldata signature) external returns (uint256 tokenId, address ipId);
71+
72+
/// @notice Updates the whitelist signer.
73+
/// @param signer_ The new whitelist signer address.
74+
function setSigner(address signer_) external;
75+
76+
/// @notice Updates the unified token URI for all badges.
77+
/// @param tokenURI_ The new token URI.
78+
function setTokenURI(string memory tokenURI_) external;
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.26;
3+
4+
/// @title Story NFT Factory Interface
5+
/// @notice Story NFT Factory is the entrypoint for creating new Story NFT collections.
6+
interface IStoryNFTFactory {
7+
////////////////////////////////////////////////////////////////////////////
8+
// Errors //
9+
////////////////////////////////////////////////////////////////////////////
10+
/// @notice Invalid signature provided to StoryNFTFactory functions.
11+
/// @param signature The signature that is invalid.
12+
error StoryNFTFactory__InvalidSignature(bytes signature);
13+
14+
/// @notice NftTemplate is not whitelisted to be used as a StoryNFT.
15+
/// @param nftTemplate The NFT template that is not whitelisted.
16+
error StoryNFTFactory__NftTemplateNotWhitelisted(address nftTemplate);
17+
18+
/// @notice Organization is already deployed by the StoryNFTFactory.
19+
/// @param orgName The name of the organization that is already deployed.
20+
/// @param deployedStoryNft The address of the already deployed StoryNFT for the organization.
21+
error StoryNFTFactory__OrgAlreadyDeployed(string orgName, address deployedStoryNft);
22+
23+
/// @notice Organization is not found in the StoryNFTFactory.
24+
/// @param orgName The name of the organization that is not found.
25+
error StoryNFTFactory__OrgNotFound(string orgName);
26+
27+
/// @notice Signature is already used to deploy a StoryNFT.
28+
/// @param signature The signature that is already used.
29+
error StoryNFTFactory__SignatureAlreadyUsed(bytes signature);
30+
31+
/// @notice BaseStoryNFT is not supported by the StoryNFTFactory.
32+
/// @param tokenContract The address of the token contract that does not implement BaseStoryNFT.
33+
error StoryNFTFactory__UnsupportedBaseStoryNFT(address tokenContract);
34+
35+
/// @notice Zero address provided as a param to StoryNFTFactory functions.
36+
error StoryNFTFactory__ZeroAddressParam();
37+
38+
////////////////////////////////////////////////////////////////////////////
39+
// Events //
40+
////////////////////////////////////////////////////////////////////////////
41+
/// @notice Emitted when a new orgnization NFT is minted and a new StoryNFT associated with it is deployed.
42+
/// @param orgName The name of the organization.
43+
/// @param orgNft The address of the organization NFT.
44+
/// @param orgTokenId The token ID of the organization NFT.
45+
/// @param orgIpId The ID of the organization IP.
46+
/// @param storyNft The address of the deployed StoryNFT.
47+
event StoryNftDeployed(string orgName, address orgNft, uint256 orgTokenId, address orgIpId, address storyNft);
48+
49+
/// @notice Emitted when the signer of the StoryNFTFactory is updated.
50+
/// @param signer The new signer of the StoryNFTFactory.
51+
event StoryNFTFactorySignerUpdated(address signer);
52+
53+
/// @notice Emitted when a new Story NFT template is whitelisted.
54+
/// @param nftTemplate The new Story NFT template that is whitelisted to be used in StoryNFTFactory.
55+
event StoryNFTFactoryNftTemplateWhitelisted(address nftTemplate);
56+
57+
////////////////////////////////////////////////////////////////////////////
58+
// Functions //
59+
////////////////////////////////////////////////////////////////////////////
60+
/// @notice Mints a new organization NFT and deploys (creates a clone of) `storyNftTemplate` as the StoryNFT
61+
/// associated with the new organization NFT.
62+
/// @param storyNftTemplate The address of a whitelisted StoryNFT template to be cloned.
63+
/// @param storyNftOwner The address of the owner of the new StoryNFT contract.
64+
/// @param orgName The name of the organization.
65+
/// @param orgTokenURI The token URI of the organization NFT.
66+
/// @param signature The signature from the StoryNFTFactory's whitelist signer. This signautre is genreated by
67+
/// having the whitelist signer sign the caller's address (msg.sender) for this `deployStoryNft` function.
68+
/// @param initData The initialization data for the StoryNFT (see {IStoryBadge-InitParams} for an example).
69+
/// @return orgTokenId The token ID of the organization NFT.
70+
/// @return orgIpId The ID of the organization IP.
71+
/// @return storyNft The address of the dployed StoryNFT
72+
function deployStoryNft(
73+
address storyNftTemplate,
74+
address storyNftOwner,
75+
string calldata orgName,
76+
string calldata orgTokenURI,
77+
bytes calldata signature,
78+
bytes calldata initData
79+
) external returns (uint256 orgTokenId, address orgIpId, address storyNft);
80+
81+
/// @notice Mints a new organization NFT and deploys (creates a clone of) `storyNftTemplate` as the StoryNFT
82+
/// associated with the new organization NFT.
83+
/// @dev Enforced to be only callable by the protocol admin in governance.
84+
/// @param storyNftTemplate The address of a whitelisted StoryNFT template to be cloned.
85+
/// @param storyNftOwner The address of the owner of the new StoryNFT contract.
86+
/// @param orgName The name of the organization.
87+
/// @param orgTokenURI The token URI of the organization NFT.
88+
/// @param initData The initialization data for the StoryNFT (see {IStoryBadge-InitParams} for an example).
89+
/// @return orgTokenId The token ID of the organization NFT.
90+
/// @return orgIpId The ID of the organization IP.
91+
/// @return storyNft The address of the dployed StoryNFT
92+
function deployByAdmin(
93+
address storyNftTemplate,
94+
address storyNftOwner,
95+
string calldata orgName,
96+
string calldata orgTokenURI,
97+
bytes calldata initData
98+
) external returns (uint256 orgTokenId, address orgIpId, address storyNft);
99+
100+
/// @notice Sets the signer of the StoryNFTFactory.
101+
/// @param signer The new signer of the StoryNFTFactory.
102+
function setSigner(address signer) external;
103+
104+
/// @notice Whitelists a new StoryNFT template.
105+
/// @param storyNftTemplate The new StoryNFT template to be whitelisted.
106+
function whitelistNftTemplate(address storyNftTemplate) external;
107+
108+
/// @notice Returns the default StoryNFT template address.
109+
function getDefaultStoryNftTemplate() external view returns (address);
110+
111+
/// @notice Returns the address of the StoryNFT for a given organization name.
112+
/// @param orgName The name of the organization.
113+
function getStoryNftAddress(string calldata orgName) external view returns (address);
114+
}

0 commit comments

Comments
 (0)