Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Private Fork Changes #175

Merged
merged 24 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cee85c4
fix: restore compatibility with latest protocol changes
sebsadface Jan 22, 2025
0e1dcb5
Update foundry_ci.yml
sebsadface Jan 22, 2025
3d4a25a
add licensing hooks to deploy script
sebsadface Jan 22, 2025
7b71014
Update BroadcastManager.s.sol
sebsadface Jan 22, 2025
b944076
Update Main.s.sol
sebsadface Jan 22, 2025
aebe7e7
Update DeployHelper.sol
sebsadface Jan 22, 2025
105d1b8
Update DeployHelper.sol
sebsadface Jan 22, 2025
d54da2e
fix grouping and hook tests
sebsadface Jan 22, 2025
a93658f
Update DeployHelper.sol
sebsadface Jan 22, 2025
87d8c91
Update RoyaltyTokenDistributionIntegration.t.sol
sebsadface Jan 22, 2025
154072d
update tests
sebsadface Jan 23, 2025
1b5c1a4
Merge pull request #1 from piplabs/fix/compatibility
sebsadface Jan 23, 2025
dc02dfd
restort backwards compatibility (#2)
sebsadface Jan 23, 2025
46c8cd4
feat: new attach default terms workflow fns (#3)
sebsadface Jan 29, 2025
20c87ec
fix:make setLicensingConfig optional (#4)
sebsadface Jan 29, 2025
6244aad
fix: replace _mint with _safeMint (#5)
sebsadface Jan 29, 2025
bc218d7
fix: ensure msg.sender matches signer (#6)
sebsadface Jan 30, 2025
9c82927
fix: allow both admin and current recipient to update mint fee recipi…
sebsadface Jan 30, 2025
56f56b0
fix: use safeERC20 (#8)
sebsadface Jan 30, 2025
6fb5c2b
fix: comments (#11)
sebsadface Jan 30, 2025
821f42c
fix: add missing initializers (#10)
sebsadface Jan 30, 2025
5069630
fix: make `nonReentrant ` precede all other modifiers (#9)
sebsadface Jan 30, 2025
096fe09
fix: allow setting TotalLicenseTokenLimit to 0 (no limit) (#12)
sebsadface Jan 30, 2025
8bd320e
chore: update package.json & gha
sebsadface Jan 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/foundry_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
with:
submodules: recursive
fetch-depth: 0

- name: Run install
uses: borales/actions-yarn@v4
with:
Expand Down
20 changes: 10 additions & 10 deletions contracts/SPGNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/ac
import { ERC721URIStorageUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import { ISPGNFT } from "./interfaces/ISPGNFT.sol";
import { Errors } from "./lib/Errors.sol";
import { SPGNFTLib } from "./lib/SPGNFTLib.sol";

contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeable {
using SafeERC20 for IERC20;

/// @dev Storage structure for the SPGNFTSotrage.
/// @param _maxSupply The maximum supply of the collection.
/// @param _totalSupply The total minted supply of the collection.
Expand Down Expand Up @@ -117,6 +120,7 @@ contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeabl
$._contractURI = initParams.contractURI;

__ERC721_init(initParams.name, initParams.symbol);
__AccessControl_init();
}

/// @notice Returns the total minted supply of the collection.
Expand Down Expand Up @@ -187,8 +191,8 @@ contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeabl
/// @dev Only callable by the fee recipient.
/// @param newFeeRecipient The new fee recipient.
function setMintFeeRecipient(address newFeeRecipient) external {
if (msg.sender != _getSPGNFTStorage()._mintFeeRecipient) {
revert Errors.SPGNFT__CallerNotFeeRecipient();
if (msg.sender != _getSPGNFTStorage()._mintFeeRecipient && !hasRole(SPGNFTLib.ADMIN_ROLE, msg.sender)) {
revert Errors.SPGNFT__CallerNotFeeRecipientOrAdmin();
}
_getSPGNFTStorage()._mintFeeRecipient = newFeeRecipient;
}
Expand Down Expand Up @@ -225,7 +229,7 @@ contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeabl
emit ContractURIUpdated();
}

/// @notice Mints an NFT from the collection. Only callable by the minter role.
/// @notice Mints an NFT from the collection. Only callable when public minting is enabled or when the caller has minter role.
/// @param to The address of the recipient of the minted NFT.
/// @param nftMetadataURI OPTIONAL. The URI of the desired metadata for the newly minted NFT.
/// @param nftMetadataHash OPTIONAL. A bytes32 hash of the NFT's metadata. This metadata is accessible via the NFT's tokenURI.
Expand Down Expand Up @@ -275,7 +279,7 @@ contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeabl
/// @dev Withdraws the contract's token balance to the fee recipient.
/// @param token The token to withdraw.
function withdrawToken(address token) public {
IERC20(token).transfer(_getSPGNFTStorage()._mintFeeRecipient, IERC20(token).balanceOf(address(this)));
IERC20(token).safeTransfer(_getSPGNFTStorage()._mintFeeRecipient, IERC20(token).balanceOf(address(this)));
}

/// @dev Supports ERC165 interface.
Expand Down Expand Up @@ -314,7 +318,7 @@ contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeabl
}

if ($._mintFeeToken != address(0) && $._mintFee > 0) {
IERC20($._mintFeeToken).transferFrom(payer, address(this), $._mintFee);
IERC20($._mintFeeToken).safeTransferFrom(payer, address(this), $._mintFee);
}

tokenId = ++$._totalSupply;
Expand All @@ -323,7 +327,7 @@ contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeabl
$._nftMetadataHashToTokenId[nftMetadataHash] = tokenId;
}

_mint(to, tokenId);
_safeMint(to, tokenId);

if (bytes(nftMetadataURI).length > 0) _setTokenURI(tokenId, nftMetadataURI);
}
Expand Down Expand Up @@ -356,10 +360,6 @@ contract SPGNFT is ISPGNFT, ERC721URIStorageUpgradeable, AccessControlUpgradeabl
_grantRole(SPGNFTLib.MINTER_ROLE, ROYALTY_TOKEN_DISTRIBUTION_WORKFLOWS_ADDRESS);
}

//
// Upgrade
//

/// @dev Returns the storage struct of SPGNFT.
function _getSPGNFTStorage() private pure returns (SPGNFTStorage storage $) {
assembly {
Expand Down
2 changes: 1 addition & 1 deletion contracts/hooks/LockLicenseHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { BaseModule } from "@storyprotocol/core/modules/BaseModule.sol";
import { ILicensingHook } from "@storyprotocol/core/interfaces/modules/licensing/ILicensingHook.sol";

contract LockLicenseHook is BaseModule, ILicensingHook {
string public constant override name = "LockLicenseHook";
string public constant override name = "LOCK_LICENSE_HOOK";

/// @notice Emitted when attempting to perform an action on a locked license
/// @param licensorIpId The licensor IP id that is locked
Expand Down
5 changes: 3 additions & 2 deletions contracts/hooks/TotalLicenseTokenLimitHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ILicenseToken } from "@storyprotocol/core/interfaces/ILicenseToken.sol"
import { ILicenseTemplate } from "@storyprotocol/core/interfaces/modules/licensing/ILicenseTemplate.sol";

contract TotalLicenseTokenLimitHook is BaseModule, AccessControlled, ILicensingHook {
string public constant override name = "TotalLicenseTokenLimitHook";
string public constant override name = "TOTAL_LICENSE_TOKEN_LIMIT_HOOK";

/// @notice The address of the License Registry.
ILicenseRegistry public immutable LICENSE_REGISTRY;
Expand Down Expand Up @@ -75,7 +75,8 @@ contract TotalLicenseTokenLimitHook is BaseModule, AccessControlled, ILicensingH
) external verifyPermission(licensorIpId) {
bytes32 key = keccak256(abi.encodePacked(licensorIpId, licenseTemplate, licenseTermsId));
uint256 totalSupply = _getTotalSupply(licensorIpId);
if (limit < totalSupply) revert TotalLicenseTokenLimitHook_LimitLowerThanTotalSupply(totalSupply, limit);
if (limit != 0 && limit < totalSupply)
revert TotalLicenseTokenLimitHook_LimitLowerThanTotalSupply(totalSupply, limit);
totalLicenseTokenLimit[key] = limit;
emit SetTotalLicenseTokenLimit(licensorIpId, licenseTemplate, licenseTermsId, limit);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/story-nft/IOrgStoryNFTFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ interface IOrgStoryNFTFactory {
/// @param orgNftRecipient The address of the recipient of the organization NFT.
/// @param orgName The name of the organization.
/// @param orgIpMetadata OPTIONAL. The desired metadata for the newly minted OrgNFT and registered IP.
/// @param signature The signature from the OrgStoryNFTFactory's whitelist signer. This signautre is generated by
/// @param signature The signature from the OrgStoryNFTFactory's whitelist signer. This signature is generated by
/// having the whitelist signer sign the caller's address (msg.sender) for this `deployOrgStoryNft` function.
/// @param storyNftInitParams The initialization parameters for StoryNFT {see {IStoryNFT-StoryNftInitParams}}.
/// @return orgNft The address of the organization NFT.
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/story-nft/IStoryBadgeNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ interface IStoryBadgeNFT is IStoryNFT, IERC721Metadata, IERC5192 {
/// @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 NFT.
/// @param signature The signature from the whitelist signer. This signautre is generated by having the whitelist
/// @param signature The signature from the whitelist signer. This signature is generated 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 NFT.
/// @return ipId The ID of the badge NFT IP.
Expand Down
46 changes: 46 additions & 0 deletions contracts/interfaces/workflows/IDerivativeWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,50 @@ interface IDerivativeWorkflows {
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadataAndRegister
) external returns (address ipId);

////////////////////////////////////////////////////////////////////////////
// DEPRECATED, WILL BE REMOVED IN V1.4 //
////////////////////////////////////////////////////////////////////////////

/// @notice Mint an NFT from a SPGNFT collection and register it as a derivative IP without license tokens.
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function mintAndRegisterIpAndMakeDerivative_deprecated(
address spgNftContract,
WorkflowStructs.MakeDerivativeDEPR calldata derivData,
WorkflowStructs.IPMetadata calldata ipMetadata,
address recipient
) external returns (address ipId, uint256 tokenId);

/// @notice Register the given NFT as a derivative IP with metadata without license tokens.
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function registerIpAndMakeDerivative_deprecated(
address nftContract,
uint256 tokenId,
WorkflowStructs.MakeDerivativeDEPR calldata derivData,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadata,
WorkflowStructs.SignatureData calldata sigRegister
) external returns (address ipId);

/// @notice Mint an NFT from a SPGNFT collection and register it as a derivative IP using license tokens.
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function mintAndRegisterIpAndMakeDerivativeWithLicenseTokens_deprecated(
address spgNftContract,
uint256[] calldata licenseTokenIds,
bytes calldata royaltyContext,
WorkflowStructs.IPMetadata calldata ipMetadata,
address recipient
) external returns (address ipId, uint256 tokenId);

/// @notice Register the given NFT as a derivative IP using license tokens.
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function registerIpAndMakeDerivativeWithLicenseTokens_deprecated(
address nftContract,
uint256 tokenId,
uint256[] calldata licenseTokenIds,
bytes calldata royaltyContext,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadata,
WorkflowStructs.SignatureData calldata sigRegister
) external returns (address ipId);
}
66 changes: 66 additions & 0 deletions contracts/interfaces/workflows/IGroupingWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface IGroupingWorkflows {
/// @param spgNftContract The address of the SPGNFT collection.
/// @param groupId The ID of the group IP to add the newly registered IP.
/// @param recipient The address of the recipient of the minted NFT.
/// @param maxAllowedRewardShare The maximum reward share percentage that can be allocated to the new IP.
/// @param licensesData The data of the licenses and their configurations to be attached to the new IP.
/// @param ipMetadata OPTIONAL. The desired metadata for the newly minted NFT and registered IP.
/// @param sigAddToGroup Signature data for addIp to the group IP via the Grouping Module.
Expand All @@ -22,6 +23,7 @@ interface IGroupingWorkflows {
address spgNftContract,
address groupId,
address recipient,
uint256 maxAllowedRewardShare,
WorkflowStructs.LicenseData[] calldata licensesData,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigAddToGroup,
Expand All @@ -33,6 +35,7 @@ interface IGroupingWorkflows {
/// @param nftContract The address of the NFT collection.
/// @param tokenId The ID of the NFT.
/// @param groupId The ID of the group IP to add the newly registered IP.
/// @param maxAllowedRewardShare The maximum reward share percentage that can be allocated to the new IP.
/// @param licensesData The data of the licenses and their configurations to be attached to the new IP.
/// @param ipMetadata OPTIONAL. The desired metadata for the newly registered IP.
/// @param sigMetadataAndAttachAndConfig Signature data for setAll (metadata), attachLicenseTerms, and
Expand All @@ -43,6 +46,7 @@ interface IGroupingWorkflows {
address nftContract,
uint256 tokenId,
address groupId,
uint256 maxAllowedRewardShare,
WorkflowStructs.LicenseData[] calldata licensesData,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadataAndAttachAndConfig,
Expand All @@ -63,11 +67,13 @@ interface IGroupingWorkflows {
/// @dev ipIds must be have the same license terms as the group IP.
/// @param groupPool The address of the group reward pool.
/// @param ipIds The IDs of the IPs to add to the newly registered group IP.
/// @param maxAllowedRewardShare The maximum reward share percentage that can be allocated to each member IP.
/// @param licenseData The data of the license and its configuration to be attached to the new group IP.
/// @return groupId The ID of the newly registered group IP.
function registerGroupAndAttachLicenseAndAddIps(
address groupPool,
address[] calldata ipIds,
uint256 maxAllowedRewardShare,
WorkflowStructs.LicenseData calldata licenseData
) external returns (address groupId);

Expand All @@ -81,4 +87,64 @@ interface IGroupingWorkflows {
address[] calldata currencyTokens,
address[] calldata memberIpIds
) external returns (uint256[] memory collectedRoyalties);

////////////////////////////////////////////////////////////////////////////
// DEPRECATED, WILL BE REMOVED IN V1.4 //
////////////////////////////////////////////////////////////////////////////

/// @notice Mint an NFT from a SPGNFT collection, register it with metadata as an IP,
/// attach license terms to the registered IP, and add it to a group IP.
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function mintAndRegisterIpAndAttachLicenseAndAddToGroup_deprecated(
address spgNftContract,
address groupId,
address recipient,
address licenseTemplate,
uint256 licenseTermsId,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigAddToGroup
) external returns (address ipId, uint256 tokenId);

/// @notice Register an NFT as IP with metadata, attach license terms to the registered IP,
/// and add it to a group IP.
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
/// @dev UPDATE REQUIRED: The sigMetadataAndAttachAndConfig permission signature data must be updated and include permissions for
/// metadata setting, license attachment, and licensing configuration permissions
function registerIpAndAttachLicenseAndAddToGroup_deprecated(
address nftContract,
uint256 tokenId,
address groupId,
address licenseTemplate,
uint256 licenseTermsId,
WorkflowStructs.IPMetadata calldata ipMetadata,
WorkflowStructs.SignatureData calldata sigMetadataAndAttachAndConfig,
WorkflowStructs.SignatureData calldata sigAddToGroup
) external returns (address ipId);

/// @notice Register a group IP with a group reward pool and attach license terms to the group IP
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function registerGroupAndAttachLicense_deprecated(
address groupPool,
address licenseTemplate,
uint256 licenseTermsId
) external returns (address groupId);

/// @notice Register a group IP with a group reward pool, attach license terms to the group IP,
/// and add individual IPs to the group IP.
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function registerGroupAndAttachLicenseAndAddIps_deprecated(
address groupPool,
address[] calldata ipIds,
address licenseTemplate,
uint256 licenseTermsId
) external returns (address groupId);

/// @notice Collect royalties for the entire group and distribute the rewards to each member IP's royalty vault
/// @notice THIS VERSION OF THE FUNCTION IS DEPRECATED, WILL BE REMOVED IN V1.4
function collectRoyaltiesAndClaimReward_deprecated(
address groupIpId,
address[] calldata currencyTokens,
uint256[] calldata groupSnapshotIds,
address[] calldata memberIpIds
) external returns (uint256[] memory collectedRoyalties);
}
Loading