Skip to content

Commit

Permalink
Merge branch 'main' into pausing
Browse files Browse the repository at this point in the history
  • Loading branch information
LeoHChen authored Apr 14, 2024
2 parents 4da4bfb + dc40dae commit 39a76ed
Show file tree
Hide file tree
Showing 17 changed files with 137 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ interface IIpRoyaltyVault {
/// @notice Adds a new revenue token to the vault
/// @param token The address of the revenue token
/// @dev Only callable by the royalty policy LAP
function addIpRoyaltyVaultTokens(address token) external;
/// @return Whether the token is added
function addIpRoyaltyVaultTokens(address token) external returns (bool);

/// @notice A function to snapshot the claimable revenue and royalty token amounts
/// @return The snapshot id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ interface IRoyaltyPolicyLAP is IRoyaltyPolicy {
uint32[] targetRoyaltyAmount
);

/// @notice Event emitted when a revenue token is added to a vault
/// @param token The address of the revenue token
/// @param vault The address of the vault
event RoyaltyTokenAddedToVault(address token, address vault);

/// @notice The state data of the LAP royalty policy
/// @param isUnlinkableToParents Indicates if the ipId is unlinkable to new parents
/// @param ipRoyaltyVault The ip royalty vault address
Expand Down
3 changes: 2 additions & 1 deletion contracts/interfaces/registries/IIPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ interface IIPAssetRegistry is IIPAccountRegistry {
function totalSupply() external view returns (uint256);

/// @notice Registers an NFT as an IP asset.
/// @param chainid The chain identifier of where the IP NFT resides.
/// @param tokenContract The address of the NFT.
/// @param tokenId The token identifier of the NFT.
/// @return id The address of the newly registered IP.
function register(address tokenContract, uint256 tokenId) external returns (address id);
function register(uint256 chainid, address tokenContract, uint256 tokenId) external returns (address id);

/// @notice Gets the canonical IP identifier associated with an IP NFT.
/// @dev This is equivalent to the address of its bound IP account.
Expand Down
5 changes: 3 additions & 2 deletions contracts/modules/royalty/policies/IpRoyaltyVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,11 @@ contract IpRoyaltyVault is IIpRoyaltyVault, ERC20SnapshotUpgradeable, Reentrancy
/// @notice Adds a new revenue token to the vault
/// @param token The address of the revenue token
/// @dev Only callable by the royalty policy LAP
function addIpRoyaltyVaultTokens(address token) external {
/// @return Whether the token was added successfully
function addIpRoyaltyVaultTokens(address token) external returns (bool) {
if (msg.sender != address(ROYALTY_POLICY_LAP)) revert Errors.IpRoyaltyVault__NotRoyaltyPolicyLAP();
IpRoyaltyVaultStorage storage $ = _getIpRoyaltyVaultStorage();
$.tokens.add(token);
return $.tokens.add(token);
}

/// @notice Snapshots the claimable revenue and royalty token amounts
Expand Down
4 changes: 3 additions & 1 deletion contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ contract RoyaltyPolicyLAP is
function onRoyaltyPayment(address caller, address ipId, address token, uint256 amount) external onlyRoyaltyModule {
RoyaltyPolicyLAPStorage storage $ = _getRoyaltyPolicyLAPStorage();
address destination = $.royaltyData[ipId].ipRoyaltyVault;
IIpRoyaltyVault(destination).addIpRoyaltyVaultTokens(token);
if (IIpRoyaltyVault(destination).addIpRoyaltyVaultTokens(token)) {
emit RoyaltyTokenAddedToVault(token, destination);
}
IERC20(token).safeTransferFrom(caller, destination, amount);
}

Expand Down
62 changes: 39 additions & 23 deletions contracts/registries/IPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,45 +56,27 @@ contract IPAssetRegistry is IIPAssetRegistry, IPAccountRegistry, ProtocolPausabl

/// @notice Registers an NFT as an IP asset.
/// @dev The IP required metadata name and URI are derived from the NFT's metadata.
/// @param chainid The chain identifier of where the IP NFT resides.
/// @param tokenContract The address of the NFT.
/// @param tokenId The token identifier of the NFT.
/// @return id The address of the newly registered IP.
function register(address tokenContract, uint256 tokenId) external whenNotPaused returns (address id) {
if (!tokenContract.supportsInterface(type(IERC721).interfaceId)) {
revert Errors.IPAssetRegistry__UnsupportedIERC721(tokenContract);
}

if (IERC721(tokenContract).ownerOf(tokenId) == address(0)) {
revert Errors.IPAssetRegistry__InvalidToken(tokenContract, tokenId);
}

if (!tokenContract.supportsInterface(type(IERC721Metadata).interfaceId)) {
revert Errors.IPAssetRegistry__UnsupportedIERC721Metadata(tokenContract);
}

id = registerIpAccount(block.chainid, tokenContract, tokenId);
function register(uint256 chainid, address tokenContract, uint256 tokenId) external whenNotPaused returns (address id) {
id = registerIpAccount(chainid, tokenContract, tokenId);
IIPAccount ipAccount = IIPAccount(payable(id));

if (bytes(ipAccount.getString("NAME")).length != 0) {
revert Errors.IPAssetRegistry__AlreadyRegistered();
}

string memory name = string.concat(
block.chainid.toString(),
": ",
IERC721Metadata(tokenContract).name(),
" #",
tokenId.toString()
);
string memory uri = IERC721Metadata(tokenContract).tokenURI(tokenId);
(string memory name, string memory uri) = _getNameAndUri(chainid, tokenContract, tokenId);
uint256 registrationDate = block.timestamp;
ipAccount.setString("NAME", name);
ipAccount.setString("URI", uri);
ipAccount.setUint256("REGISTRATION_DATE", registrationDate);

_getIPAssetRegistryStorage().totalSupply++;

emit IPRegistered(id, block.chainid, tokenContract, tokenId, name, uri, registrationDate);
emit IPRegistered(id, chainid, tokenContract, tokenId, name, uri, registrationDate);
}

/// @notice Gets the canonical IP identifier associated with an IP NFT.
Expand Down Expand Up @@ -124,6 +106,40 @@ contract IPAssetRegistry is IIPAssetRegistry, IPAccountRegistry, ProtocolPausabl
return _getIPAssetRegistryStorage().totalSupply;
}

/// @dev Retrieves the name and URI of from IP NFT.
function _getNameAndUri(
uint256 chainid,
address tokenContract,
uint256 tokenId
) internal view returns (string memory name, string memory uri) {
if (chainid != block.chainid) {
name = string.concat(chainid.toString(), ": ", tokenContract.toHexString(), " #", tokenId.toString());
uri = "";
return (name, uri);
}
// Handle NFT on the same chain
if (!tokenContract.supportsInterface(type(IERC721).interfaceId)) {
revert Errors.IPAssetRegistry__UnsupportedIERC721(tokenContract);
}

if (IERC721(tokenContract).ownerOf(tokenId) == address(0)) {
revert Errors.IPAssetRegistry__InvalidToken(tokenContract, tokenId);
}

if (!tokenContract.supportsInterface(type(IERC721Metadata).interfaceId)) {
revert Errors.IPAssetRegistry__UnsupportedIERC721Metadata(tokenContract);
}

name = string.concat(
block.chainid.toString(),
": ",
IERC721Metadata(tokenContract).name(),
" #",
tokenId.toString()
);
uri = IERC721Metadata(tokenContract).tokenURI(tokenId);
}

/// @dev Hook to authorize the upgrade according to UUPSUpgradeable
/// @param newImplementation The address of the new implementation
function _authorizeUpgrade(address newImplementation) internal override restricted {}
Expand Down
2 changes: 1 addition & 1 deletion test/foundry/integration/BaseIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ contract BaseIntegration is BaseTest {
});

vm.startPrank(owner);
return ipAssetRegistry.register(nft, tokenId);
return ipAssetRegistry.register(block.chainid, nft, tokenId);
}

function registerIpAccount(MockERC721 nft, uint256 tokenId, address caller) internal returns (address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,11 @@ contract e2e is Test {
uint256 tokenId6 = mockNft.mint(dave);
uint256 tokenId7 = mockNft.mint(eve);

ipId1 = ipAssetRegistry.register(address(mockNft), tokenId1);
ipId2 = ipAssetRegistry.register(address(mockNft), tokenId2);
ipId3 = ipAssetRegistry.register(address(mockNft), tokenId3);
ipId6 = ipAssetRegistry.register(address(mockNft), tokenId6);
ipId7 = ipAssetRegistry.register(address(mockNft), tokenId7);
ipId1 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId1);
ipId2 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId2);
ipId3 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId3);
ipId6 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId6);
ipId7 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId7);

// register license terms
uint256 lcId1 = piLicenseTemplate.registerLicenseTerms(PILFlavors.nonCommercialSocialRemixing());
Expand Down
2 changes: 1 addition & 1 deletion test/foundry/modules/dispute/ArbitrationPolicySP.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ contract TestArbitrationPolicySP is BaseTest {
vm.label(expectedAddr, "IPAccount0");

vm.startPrank(u.admin);
ipAddr = ipAssetRegistry.register(address(mockNFT), 0);
ipAddr = ipAssetRegistry.register(block.chainid, address(mockNFT), 0);

licensingModule.attachLicenseTerms(ipAddr, address(pilTemplate), getSelectedPILicenseTermsId("cheap_flexible"));

Expand Down
4 changes: 2 additions & 2 deletions test/foundry/modules/dispute/DisputeModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ contract DisputeModuleTest is BaseTest {
);

vm.startPrank(u.alice);
ipAddr = ipAssetRegistry.register(address(mockNFT), 0);
ipAddr = ipAssetRegistry.register(block.chainid, address(mockNFT), 0);
licensingModule.attachLicenseTerms(ipAddr, address(pilTemplate), getSelectedPILicenseTermsId("cheap_flexible"));

// Bob mints 1 license of policy "pil-commercial-remix" from IPAccount1 and registers the derivative IP for
Expand All @@ -107,7 +107,7 @@ contract DisputeModuleTest is BaseTest {
royaltyContext: ""
}); // first license minted

ipAddr2 = ipAssetRegistry.register(address(mockNFT), 1);
ipAddr2 = ipAssetRegistry.register(block.chainid, address(mockNFT), 1);

licensingModule.registerDerivativeWithLicenseTokens(ipAddr2, licenseIds, "");

Expand Down
8 changes: 4 additions & 4 deletions test/foundry/modules/licensing/LicensingModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ contract LicensingModuleTest is BaseTest {
mockNft.mintId(ipOwner3, tokenId3);
mockNft.mintId(ipOwner5, tokenId5);

ipId1 = ipAssetRegistry.register(address(mockNft), tokenId1);
ipId2 = ipAssetRegistry.register(address(mockNft), tokenId2);
ipId3 = ipAssetRegistry.register(address(mockNft), tokenId3);
ipId5 = ipAssetRegistry.register(address(mockNft), tokenId5);
ipId1 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId1);
ipId2 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId2);
ipId3 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId3);
ipId5 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId5);

vm.label(ipId1, "IPAccount1");
vm.label(ipId2, "IPAccount2");
Expand Down
8 changes: 4 additions & 4 deletions test/foundry/modules/licensing/PILicenseTemplate.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ contract PILicenseTemplateTest is BaseTest {
mockNft.mintId(ipOwner3, tokenId3);
mockNft.mintId(ipOwner5, tokenId5);

ipId1 = ipAssetRegistry.register(address(mockNft), tokenId1);
ipId2 = ipAssetRegistry.register(address(mockNft), tokenId2);
ipId3 = ipAssetRegistry.register(address(mockNft), tokenId3);
ipId5 = ipAssetRegistry.register(address(mockNft), tokenId5);
ipId1 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId1);
ipId2 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId2);
ipId3 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId3);
ipId5 = ipAssetRegistry.register(block.chainid, address(mockNft), tokenId5);

vm.label(ipId1, "IPAccount1");
vm.label(ipId2, "IPAccount2");
Expand Down
8 changes: 4 additions & 4 deletions test/foundry/modules/metadata/CoreMetadataModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ contract CoreMetadataModuleTest is BaseTest {

mockNFT.mintId(alice, 1);

ipAccount = IIPAccount(payable(ipAssetRegistry.register(address(mockNFT), 1)));
ipAccount = IIPAccount(payable(ipAssetRegistry.register(block.chainid, address(mockNFT), 1)));

vm.label(address(ipAccount), "IPAccount1");
}
Expand All @@ -39,7 +39,7 @@ contract CoreMetadataModuleTest is BaseTest {
assertEq(ipAccount.getBytes32(address(coreMetadataModule), "NFT_METADATA_HASH"), bytes32("0x1234"));

mockNFT.mintId(alice, 2);
IIPAccount ipAccount2 = IIPAccount(payable(ipAssetRegistry.register(address(mockNFT), 2)));
IIPAccount ipAccount2 = IIPAccount(payable(ipAssetRegistry.register(block.chainid, address(mockNFT), 2)));
vm.label(address(ipAccount2), "IPAccount2");

vm.prank(alice);
Expand Down Expand Up @@ -97,7 +97,7 @@ contract CoreMetadataModuleTest is BaseTest {
assertEq(ipAccount.getBytes32(address(coreMetadataModule), "METADATA_HASH"), bytes32("0x1234"));

mockNFT.mintId(alice, 2);
IIPAccount ipAccount2 = IIPAccount(payable(ipAssetRegistry.register(address(mockNFT), 2)));
IIPAccount ipAccount2 = IIPAccount(payable(ipAssetRegistry.register(block.chainid, address(mockNFT), 2)));
vm.label(address(ipAccount2), "IPAccount2");

vm.prank(alice);
Expand Down Expand Up @@ -212,7 +212,7 @@ contract CoreMetadataModuleTest is BaseTest {
coreMetadataModule.updateNftTokenURI(address(ipAccount), bytes32("0x1234"));

mockNFT.mintId(alice, 2);
IIPAccount ipAccount2 = IIPAccount(payable(ipAssetRegistry.register(address(mockNFT), 2)));
IIPAccount ipAccount2 = IIPAccount(payable(ipAssetRegistry.register(block.chainid, address(mockNFT), 2)));
vm.label(address(ipAccount2), "IPAccount2");

coreMetadataModule.setMetadataURI(address(ipAccount2), "My MetadataURI2", bytes32("0x5678"));
Expand Down
2 changes: 1 addition & 1 deletion test/foundry/modules/metadata/CoreMetadataViewModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract CoreMetadataViewModuleTest is BaseTest {

mockNFT.mintId(alice, 99);

ipAccount = IIPAccount(payable(ipAssetRegistry.register(address(mockNFT), 99)));
ipAccount = IIPAccount(payable(ipAssetRegistry.register(block.chainid, address(mockNFT), 99)));

vm.label(address(ipAccount), "IPAccount1");
}
Expand Down
2 changes: 1 addition & 1 deletion test/foundry/modules/royalty/RoyaltyModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ contract TestRoyaltyModule is BaseTest {
vm.label(expectedAddr, "IPAccount0");

vm.startPrank(u.alice);
ipAddr = ipAssetRegistry.register(address(mockNFT), 0);
ipAddr = ipAssetRegistry.register(block.chainid, address(mockNFT), 0);

licensingModule.attachLicenseTerms(ipAddr, address(pilTemplate), getSelectedPILicenseTermsId("cheap_flexible"));

Expand Down
Loading

0 comments on commit 39a76ed

Please sign in to comment.