Skip to content

Commit

Permalink
fix: inherit IERC165 & additional checks in tokenizer
Browse files Browse the repository at this point in the history
  • Loading branch information
sebsadface committed Dec 15, 2024
1 parent 7e61975 commit 8efd8a2
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 7 deletions.
5 changes: 1 addition & 4 deletions contracts/interfaces/modules/tokenizer/IOwnableERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.26;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/// @title Ownable ERC20 Interface
/// @notice Interface for the Ownable ERC20 token
Expand Down Expand Up @@ -29,8 +30,4 @@ interface IOwnableERC20 is IERC20 {

/// @notice Returns the upgradable beacon
function upgradableBeacon() external view returns (address);

/// @notice Returns whether the contract supports an interface
/// @param interfaceId The interface ID
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
10 changes: 10 additions & 0 deletions contracts/interfaces/modules/tokenizer/ITokenizerModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,14 @@ interface ITokenizerModule is IModule {
/// @param initData The initialization data for the token
/// @return token The address of the newly created token
function tokenize(address ipId, address tokenTemplate, bytes calldata initData) external returns (address token);

/// @notice Returns the fractionalized token for an IP
/// @param ipId The address of the IP
/// @return token The address of the token
function getFractionalizedToken(address ipId) external view returns (address token);

/// @notice Checks if a token template is whitelisted
/// @param tokenTemplate The address of the token template
/// @return allowed The whitelisting status (true if whitelisted, false if not)
function isWhitelistedTokenTemplate(address tokenTemplate) external view returns (bool allowed);
}
10 changes: 10 additions & 0 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,27 @@ library Errors {
error TokenizerModule__ZeroTokenTemplate();

/// @notice Token template is not supported.
/// @param tokenTemplate The address of the token template that is not supported
error TokenizerModule__UnsupportedERC20(address tokenTemplate);

/// @notice IP is disputed.
/// @param ipId The address of the disputed IP
error TokenizerModule__DisputedIpId(address ipId);

/// @notice Token template is not whitelisted.
/// @param tokenTemplate The address of the token template
error TokenizerModule__TokenTemplateNotWhitelisted(address tokenTemplate);

/// @notice IP is not registered.
/// @param ipId The address of the IP
error TokenizerModule__IpNotRegistered(address ipId);

/// @notice IP is expired.
/// @param ipId The address of the expired IP
error TokenizerModule__IpExpired(address ipId);

/// @notice IP is already tokenized.
/// @param ipId The address of the already tokenized IP
/// @param token The address of the fractionalized token for the IP
error TokenizerModule__IpAlreadyTokenized(address ipId, address token);
}
30 changes: 27 additions & 3 deletions contracts/modules/tokenizer/TokenizerModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
pragma solidity 0.8.26;

import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";

import { BaseModule } from "@storyprotocol/core/modules/BaseModule.sol";
import { AccessControlled } from "@storyprotocol/core/access/AccessControlled.sol";
Expand All @@ -27,6 +28,7 @@ contract TokenizerModule is
BaseModule,
AccessControlled,
ProtocolPausableUpgradeable,
ReentrancyGuardUpgradeable,
UUPSUpgradeable
{
using Strings for *;
Expand All @@ -35,9 +37,11 @@ contract TokenizerModule is

/// @dev Storage structure for the TokenizerModule
/// @param isWhitelistedTokenTemplate Mapping of token templates to their whitelisting status
/// @param fractionalizedTokens Mapping of IP IDs to their fractionalized tokens
/// @custom:storage-location erc7201:story-protocol-periphery.TokenizerModule
struct TokenizerModuleStorage {
mapping(address => bool) isWhitelistedTokenTemplate;
mapping(address ipId => address token) fractionalizedTokens;
}

/// solhint-disable-next-line max-line-length
Expand Down Expand Up @@ -76,7 +80,7 @@ contract TokenizerModule is
emit TokenTemplateWhitelisted(tokenTemplate, allowed);
}

/// @notice Tokenizes an IP
/// @notice Tokenizes (fractionalizes) an IP
/// @param ipId The address of the IP
/// @param tokenTemplate The address of the token template
/// @param initData The initialization data for the token
Expand All @@ -85,12 +89,14 @@ contract TokenizerModule is
address ipId,
address tokenTemplate,
bytes calldata initData
) external verifyPermission(ipId) returns (address token) {
) external verifyPermission(ipId) nonReentrant returns (address token) {
if (DISPUTE_MODULE.isIpTagged(ipId)) revert Errors.TokenizerModule__DisputedIpId(ipId);
if (!IP_ASSET_REGISTRY.isRegistered(ipId)) revert Errors.TokenizerModule__IpNotRegistered(ipId);
if (_isExpiredNow(ipId)) revert Errors.TokenizerModule__IpExpired(ipId);

TokenizerModuleStorage storage $ = _getTokenizerModuleStorage();
address existingToken = $.fractionalizedTokens[ipId];
if (existingToken != address(0)) revert Errors.TokenizerModule__IpAlreadyTokenized(ipId, existingToken);
if (!$.isWhitelistedTokenTemplate[tokenTemplate])
revert Errors.TokenizerModule__TokenTemplateNotWhitelisted(tokenTemplate);

Expand All @@ -101,9 +107,27 @@ contract TokenizerModule is
)
);

$.fractionalizedTokens[ipId] = token;

emit IPTokenized(ipId, token);
}

/// @notice Returns the fractionalized token for an IP
/// @param ipId The address of the IP
/// @return token The address of the token (0 address if IP has not been tokenized)
function getFractionalizedToken(address ipId) external view returns (address token) {
TokenizerModuleStorage storage $ = _getTokenizerModuleStorage();
return $.fractionalizedTokens[ipId];
}

/// @notice Checks if a token template is whitelisted
/// @param tokenTemplate The address of the token template
/// @return allowed The whitelisting status (true if whitelisted, false if not)
function isWhitelistedTokenTemplate(address tokenTemplate) external view returns (bool allowed) {
TokenizerModuleStorage storage $ = _getTokenizerModuleStorage();
return $.isWhitelistedTokenTemplate[tokenTemplate];
}

/// @dev Check if an IP is expired now
/// @param ipId The address of the IP
function _isExpiredNow(address ipId) internal view returns (bool) {
Expand Down

0 comments on commit 8efd8a2

Please sign in to comment.