diff --git a/contracts/registry/DIDRegistry.sol b/contracts/registry/DIDRegistry.sol index 0986772a..322f2c8d 100644 --- a/contracts/registry/DIDRegistry.sol +++ b/contracts/registry/DIDRegistry.sol @@ -47,7 +47,7 @@ contract DIDRegistry is DIDFactory { } /** - * @notice Register a Mintable DID. + * @notice Register a Mintable DID using NFTs based in the ERC-1155 standard. * * @dev The first attribute of a DID registered sets the DID owner. * Subsequent updates record _checksum and update info. @@ -60,7 +60,7 @@ contract DIDRegistry is DIDFactory { * @param _royalties refers to the royalties to reward to the DID creator in the secondary market * @param _mint if true it mints the ERC-1155 NFTs attached to the asset * @param _activityId refers to activity - * @param _attributes refers to the provenance attributes + * @param _nftMetadata refers to the url providing the NFT Metadata * @return size refers to the size of the registry after the register action. */ function registerMintableDID( @@ -72,22 +72,65 @@ contract DIDRegistry is DIDFactory { uint8 _royalties, bool _mint, bytes32 _activityId, - string memory _attributes + string memory _nftMetadata ) public - onlyValidAttributes(_attributes) + onlyValidAttributes(_nftMetadata) returns (uint size) { - uint result = registerDID(_didSeed, _checksum, _providers, _url, _activityId, _attributes); + uint result = registerDID(_didSeed, _checksum, _providers, _url, _activityId, ''); enableAndMintDidNft( hashDID(_didSeed, msg.sender), _cap, _royalties, - _mint + _mint, + _nftMetadata ); return result; - } - + } + + /** + * @notice Register a Mintable DID using NFTs based in the ERC-721 standard. + * + * @dev The first attribute of a DID registered sets the DID owner. + * Subsequent updates record _checksum and update info. + * + * @param _didSeed refers to decentralized identifier seed (a bytes32 length ID). + * @param _checksum includes a one-way HASH calculated using the DDO content. + * @param _providers list of addresses that can act as an asset provider + * @param _url refers to the url resolving the DID into a DID Document (DDO), limited to 2048 bytes. + * @param _royalties refers to the royalties to reward to the DID creator in the secondary market + * @param _mint if true it mints the ERC-1155 NFTs attached to the asset + * @param _activityId refers to activity + * @param _nftMetadata refers to the url providing the NFT Metadata + * @return size refers to the size of the registry after the register action. + */ + function registerMintableDID721( + bytes32 _didSeed, + bytes32 _checksum, + address[] memory _providers, + string memory _url, + uint8 _royalties, + bool _mint, + bytes32 _activityId, + string memory _nftMetadata + ) + public + onlyValidAttributes(_nftMetadata) + returns (uint size) + { + uint result = registerDID(_didSeed, _checksum, _providers, _url, _activityId, ''); + enableAndMintDidNft721( + hashDID(_didSeed, msg.sender), + _royalties, + _mint, + _nftMetadata + ); + return result; + } + + + /** * @notice Register a Mintable DID. * @@ -101,7 +144,7 @@ contract DIDRegistry is DIDFactory { * @param _cap refers to the mint cap * @param _royalties refers to the royalties to reward to the DID creator in the secondary market * @param _activityId refers to activity - * @param _attributes refers to the provenance attributes + * @param _nftMetadata refers to the url providing the NFT Metadata * @return size refers to the size of the registry after the register action. */ function registerMintableDID( @@ -112,19 +155,19 @@ contract DIDRegistry is DIDFactory { uint256 _cap, uint8 _royalties, bytes32 _activityId, - string memory _attributes + string memory _nftMetadata ) public - onlyValidAttributes(_attributes) + onlyValidAttributes(_nftMetadata) returns (uint size) { return registerMintableDID( - _didSeed, _checksum, _providers, _url, _cap, _royalties, false, _activityId, _attributes); + _didSeed, _checksum, _providers, _url, _cap, _royalties, false, _activityId, _nftMetadata); } /** - * @notice enableDidNft creates the initial setup of NFTs minting and royalties distribution. + * @notice enableDidNft creates the initial setup of NFTs minting and royalties distribution for ERC-1155 NFTs. * After this initial setup, this data can't be changed anymore for the DID given, even for the owner of the DID. * The reason of this is to avoid minting additional NFTs after the initial agreement, what could affect the * valuation of NFTs of a DID already created. @@ -134,32 +177,52 @@ contract DIDRegistry is DIDFactory { * @param _cap refers to the mint cap * @param _royalties refers to the royalties to reward to the DID creator in the secondary market * @param _mint if is true mint directly the amount capped tokens and lock in the _lockAddress + * @param _nftMetadata refers to the url providing the NFT Metadata */ function enableAndMintDidNft( bytes32 _did, uint256 _cap, uint8 _royalties, - bool _mint + bool _mint, + string memory _nftMetadata ) public onlyDIDOwner(_did) returns (bool success) { didRegisterList.initializeNftConfig(_did, _cap, _royalties); - - if (_mint) { + + if (bytes(_nftMetadata).length > 0) + erc1155.setNFTMetadata(uint256(_did), _nftMetadata); + + if (_royalties > 0) + erc1155.setTokenRoyalty(uint256(_did), msg.sender, _royalties); + + if (_mint) mint(_did, _cap); - } return super.used( keccak256(abi.encode(_did, _cap, _royalties, msg.sender)), _did, msg.sender, keccak256('enableNft'), '', 'nft initialization'); } - + + /** + * @notice enableAndMintDidNft721 creates the initial setup of NFTs minting and royalties distribution for ERC-721 NFTs. + * After this initial setup, this data can't be changed anymore for the DID given, even for the owner of the DID. + * The reason of this is to avoid minting additional NFTs after the initial agreement, what could affect the + * valuation of NFTs of a DID already created. + + * @dev update the DID registry providers list by adding the mintCap and royalties configuration + * @param _did refers to decentralized identifier (a byte32 length ID) + * @param _royalties refers to the royalties to reward to the DID creator in the secondary market + * @param _mint if is true mint directly the amount capped tokens and lock in the _lockAddress + * @param _nftMetadata refers to the url providing the NFT Metadata + */ function enableAndMintDidNft721( bytes32 _did, uint8 _royalties, - bool _mint + bool _mint, + string memory _nftMetadata ) public onlyDIDOwner(_did) @@ -167,9 +230,14 @@ contract DIDRegistry is DIDFactory { { didRegisterList.initializeNft721Config(_did, _royalties); - if (_mint) { + if (bytes(_nftMetadata).length > 0) + erc721.setNFTMetadata(uint256(_did), _nftMetadata); + + if (_royalties > 0) + erc721.setTokenRoyalty(uint256(_did), msg.sender, _royalties); + + if (_mint) mint721(_did); - } return super.used( keccak256(abi.encode(_did, 1, _royalties, msg.sender)), diff --git a/contracts/registry/DIDRegistryLibrary.sol b/contracts/registry/DIDRegistryLibrary.sol index 9fe4a6a3..a5a725f1 100644 --- a/contracts/registry/DIDRegistryLibrary.sol +++ b/contracts/registry/DIDRegistryLibrary.sol @@ -120,7 +120,7 @@ library DIDRegistryLibrary { require(!_self.didRegisters[_did].nftInitialized, 'NFT already initialized'); - require(_royalties < 100, 'Invalid royalties number'); + require(_royalties <= 100, 'Invalid royalties number'); require(_royalties >= _self.didRegisters[_did].royalties, 'Cannot decrease royalties'); _self.didRegisters[_did].mintCap = _cap; diff --git a/contracts/token/NFTBase.sol b/contracts/token/NFTBase.sol new file mode 100644 index 00000000..7017c610 --- /dev/null +++ b/contracts/token/NFTBase.sol @@ -0,0 +1,92 @@ +pragma solidity ^0.8.0; +// Copyright 2020 Keyko GmbH. +// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) +// Code is Apache-2.0 and docs are CC-BY-4.0 + +import '@openzeppelin/contracts-upgradeable/interfaces/IERC2981Upgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; +import '@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol'; + +/** + * + * @dev Implementation of the Royalties EIP-2981 base contract + * See https://eips.ethereum.org/EIPS/eip-2981 + */ +abstract contract NFTBase is IERC2981Upgradeable, OwnableUpgradeable, AccessControlUpgradeable { + + // Mapping from account to proxy approvals + mapping (address => bool) internal _proxyApprovals; + + bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE'); + + struct RoyaltyInfo { + address receiver; + uint256 royaltyAmount; + } + + struct NFTMetadata { + string nftURI; + } + + // Mapping of Royalties per tokenId (DID) + mapping(uint256 => RoyaltyInfo) internal _royalties; + + mapping(uint256 => NFTMetadata) internal _metadata; + + /** + * Event for recording proxy approvals. + */ + event ProxyApproval(address sender, address operator, bool approved); + + + function setProxyApproval( + address operator, + bool approved + ) + public + onlyOwner + virtual + { + _proxyApprovals[operator] = approved; + emit ProxyApproval(_msgSender(), operator, approved); + } + + function _setNFTMetadata( + uint256 tokenId, + string memory tokenURI + ) + internal + { + _metadata[tokenId] = NFTMetadata(tokenURI); + } + + function _setTokenRoyalty( + uint256 tokenId, + address receiver, + uint256 royaltyAmount + ) + internal + { + require(royaltyAmount <= 100, 'ERC2981Royalties: Too high'); + _royalties[tokenId] = RoyaltyInfo(receiver, royaltyAmount); + } + + /** + * @inheritdoc IERC2981Upgradeable + */ + function royaltyInfo( + uint256 tokenId, + uint256 value + ) + external + view + override + returns (address receiver, uint256 royaltyAmount) + { + RoyaltyInfo memory royalties = _royalties[tokenId]; + receiver = royalties.receiver; + royaltyAmount = (value * royalties.royaltyAmount) / 100; + } + +} diff --git a/contracts/token/erc1155/NFTUpgradeable.sol b/contracts/token/erc1155/NFTUpgradeable.sol index 45b7aa8f..7c71660f 100644 --- a/contracts/token/erc1155/NFTUpgradeable.sol +++ b/contracts/token/erc1155/NFTUpgradeable.sol @@ -3,26 +3,15 @@ pragma solidity ^0.8.0; import '@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol'; +import '../NFTBase.sol'; /** * * @dev Implementation of the basic standard multi-token. * See https://eips.ethereum.org/EIPS/eip-1155 */ -contract NFTUpgradeable is ERC1155Upgradeable, OwnableUpgradeable, AccessControlUpgradeable { - - // Mapping from account to proxy approvals - mapping (address => bool) private _proxyApprovals; - - bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE'); +contract NFTUpgradeable is ERC1155Upgradeable, NFTBase { - /** - * Event for recording proxy approvals. - */ - event ProxyApproval(address sender, address operator, bool approved); - /** * @dev See {_setURI}. */ @@ -35,13 +24,7 @@ contract NFTUpgradeable is ERC1155Upgradeable, OwnableUpgradeable, AccessControl AccessControlUpgradeable.__AccessControl_init(); AccessControlUpgradeable._setupRole(MINTER_ROLE, msg.sender); } - - function setProxyApproval(address operator, bool approved) public onlyOwner virtual { - _proxyApprovals[operator] = approved; - emit ProxyApproval(_msgSender(), operator, approved); - } - /** * @dev See {IERC1155-isApprovedForAll}. */ @@ -63,9 +46,55 @@ contract NFTUpgradeable is ERC1155Upgradeable, OwnableUpgradeable, AccessControl AccessControlUpgradeable._setupRole(MINTER_ROLE, account); } - function supportsInterface(bytes4 interfaceId) public view virtual override(AccessControlUpgradeable, ERC1155Upgradeable) returns (bool) { +// function uri(uint256 id) external view returns (string memory) + function uri(uint256 tokenId) public view override returns (string memory) { + return _metadata[tokenId].nftURI; + } + + /** + * @dev Record some NFT Metadata + * @param tokenId the id of the asset with the royalties associated + * @param nftURI the URI (https, ipfs, etc) to the metadata describing the NFT + */ + function setNFTMetadata( + uint256 tokenId, + string memory nftURI + ) + public + { + require(hasRole(MINTER_ROLE, msg.sender), 'only minter'); + _setNFTMetadata(tokenId, nftURI); + } + + /** + * @dev Record the asset royalties + * @param tokenId the id of the asset with the royalties associated + * @param receiver the receiver of the royalties (the original creator) + * @param royaltyAmount percentage (no decimals, between 0 and 100) + */ + function setTokenRoyalty( + uint256 tokenId, + address receiver, + uint256 royaltyAmount + ) + public + { + require(hasRole(MINTER_ROLE, msg.sender), 'only minter'); + _setTokenRoyalty(tokenId, receiver, royaltyAmount); + } + + function supportsInterface( + bytes4 interfaceId + ) + public + view + virtual + override(ERC1155Upgradeable, IERC165Upgradeable) + returns (bool) + { return AccessControlUpgradeable.supportsInterface(interfaceId) - || ERC1155Upgradeable.supportsInterface(interfaceId); + || ERC1155Upgradeable.supportsInterface(interfaceId) + || interfaceId == type(IERC2981Upgradeable).interfaceId; } } diff --git a/contracts/token/erc721/NFT721Upgradeable.sol b/contracts/token/erc721/NFT721Upgradeable.sol index b472eff2..4e26297f 100644 --- a/contracts/token/erc721/NFT721Upgradeable.sol +++ b/contracts/token/erc721/NFT721Upgradeable.sol @@ -3,24 +3,13 @@ pragma solidity ^0.8.0; import '@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol'; +import '../NFTBase.sol'; /** * * @dev Implementation of the basic standard multi-token. */ -contract NFT721Upgradeable is ERC721Upgradeable, OwnableUpgradeable, AccessControlUpgradeable { - - // Mapping from account to proxy approvals - mapping (address => bool) private _proxyApprovals; - - bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE'); - - /** - * Event for recording proxy approvals. - */ - event ProxyApproval(address sender, address operator, bool approved); +contract NFT721Upgradeable is ERC721Upgradeable, NFTBase { /** * @dev See {_setURI}. @@ -34,20 +23,18 @@ contract NFT721Upgradeable is ERC721Upgradeable, OwnableUpgradeable, AccessContr AccessControlUpgradeable.__AccessControl_init(); AccessControlUpgradeable._setupRole(MINTER_ROLE, msg.sender); } - - function setProxyApproval(address operator, bool approved) public onlyOwner virtual { - _proxyApprovals[operator] = approved; - emit ProxyApproval(_msgSender(), operator, approved); - } - /** * @dev See {IERC1155-isApprovedForAll}. */ function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { return super.isApprovedForAll(account, operator) || _proxyApprovals[operator]; } - + + function addMinter(address account) public onlyOwner { + AccessControlUpgradeable._setupRole(MINTER_ROLE, account); + } + function mint(address to, uint256 id) public { require(hasRole(MINTER_ROLE, msg.sender), 'only minter can mint'); _mint(to, id); @@ -57,14 +44,55 @@ contract NFT721Upgradeable is ERC721Upgradeable, OwnableUpgradeable, AccessContr require(hasRole(MINTER_ROLE, msg.sender), 'only minter can burn'); _burn(id); } + + function tokenURI(uint256 tokenId) public view override returns (string memory) { + return _metadata[tokenId].nftURI; + } - function addMinter(address account) public onlyOwner { - AccessControlUpgradeable._setupRole(MINTER_ROLE, account); + /** + * @dev Record some NFT Metadata + * @param tokenId the id of the asset with the royalties associated + * @param nftURI the URI (https, ipfs, etc) to the metadata describing the NFT + */ + function setNFTMetadata( + uint256 tokenId, + string memory nftURI + ) + public + { + require(hasRole(MINTER_ROLE, msg.sender), 'only minter'); + _setNFTMetadata(tokenId, nftURI); + } + + /** + * @dev Record the asset royalties + * @param tokenId the id of the asset with the royalties associated + * @param receiver the receiver of the royalties (the original creator) + * @param royaltyAmount percentage (no decimals, between 0 and 100) + */ + function setTokenRoyalty( + uint256 tokenId, + address receiver, + uint256 royaltyAmount + ) + public + { + require(hasRole(MINTER_ROLE, msg.sender), 'only minter'); + _setTokenRoyalty(tokenId, receiver, royaltyAmount); } - function supportsInterface(bytes4 interfaceId) public view virtual override(AccessControlUpgradeable, ERC721Upgradeable) returns (bool) { + function supportsInterface( + bytes4 interfaceId + ) + public + view + virtual + override(ERC721Upgradeable, IERC165Upgradeable) + returns (bool) + { return AccessControlUpgradeable.supportsInterface(interfaceId) - || ERC721Upgradeable.supportsInterface(interfaceId); + || ERC721Upgradeable.supportsInterface(interfaceId) + || interfaceId == type(IERC2981Upgradeable).interfaceId; } } diff --git a/package.json b/package.json index b9c58402..c393e79a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nevermined-io/contracts", - "version": "1.3.2", + "version": "1.3.3", "description": "Nevermined implementation of Nevermined in Solidity", "bugs": { "url": "https://github.com/nevermined-io/contracts/issues" diff --git a/pom.xml b/pom.xml index 98c86690..e46723ef 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.keyko.nevermined contracts jar - 1.3.2 + 1.3.3 Nevermined Contracts Nevermined Data Platform Smart Contracts in Solidity https://github.com/nevermined-io/contracts diff --git a/setup.py b/setup.py index 6eaac8a3..b86be491 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,6 @@ test_suite='tests', tests_require=test_requirements, url='https://github.com/nevermined-io/contracts', - version='1.3.2', + version='1.3.3', zip_safe=False, ) diff --git a/test/int/nft/NFT721_e2e.Test.js b/test/int/nft/NFT721_e2e.Test.js index a1c4f425..485693a8 100644 --- a/test/int/nft/NFT721_e2e.Test.js +++ b/test/int/nft/NFT721_e2e.Test.js @@ -23,8 +23,7 @@ const NeverminedToken = artifacts.require('NeverminedToken') const NFTAccessCondition = artifacts.require('NFTAccessCondition') const NFTHolderCondition = artifacts.require('NFT721HolderCondition') -const TestERC721 = artifacts.require('TestERC721') -const VitaDAOERC721 = artifacts.require('IPNFT') +const TestERC721 = artifacts.require('NFT721Upgradeable') const constants = require('../../helpers/constants.js') const { getBalance } = require('../../helpers/getBalance.js') @@ -32,7 +31,6 @@ const testUtils = require('../../helpers/utils.js') contract('End to End NFT721 Scenarios', (accounts) => { const royalties = 10 // 10% of royalties in the secondary market - const cappedAmount = 5 const didSeed = testUtils.generateId() let did const agreementId = testUtils.generateId() @@ -92,8 +90,13 @@ contract('End to End NFT721 Scenarios', (accounts) => { token = await NeverminedToken.new() await token.initialize(owner, owner) + nft = await TestERC721.new({ from: deployer }) + await nft.initialize({ from: owner }) + didRegistry = await DIDRegistry.new() - await didRegistry.initialize(owner, constants.address.zero, constants.address.zero) + await didRegistry.initialize(owner, constants.address.zero, nft.address) + + await nft.addMinter(didRegistry.address) conditionStoreManager = await ConditionStoreManager.new() @@ -502,37 +505,13 @@ contract('End to End NFT721 Scenarios', (accounts) => { describe('Test NFT721', () => { describe('As an artist I want to register a new artwork', () => { it('I want to register a new artwork and tokenize (via NFT). I want to get 10% of royalties', async () => { - nft = await TestERC721.new({ from: deployer }) - await nft.initialize({ from: owner }) - - const { didRegistry } = await setupTest() - - did = await didRegistry.hashDID(didSeed, artist) - - await didRegistry.registerMintableDID( - didSeed, checksum, [], url, cappedAmount, royalties, constants.activities.GENERATED, '', { from: artist }) - - await nft.mint(did, { from: artist }) - await nft.setApprovalForAll(transferCondition.address, true, { from: artist }) - }) - }) - - runTests() - }) - - describe('VitaDAO NFT721', () => { - describe('As an artist I want to register a new artwork', () => { - it('I want to register a new artwork and tokenize (via NFT). I want to get 10% of royalties', async () => { - nft = await VitaDAOERC721.new({ from: deployer }) - await nft.initialize('VitaNFT', 'VitaNFT', { from: owner }) const { didRegistry } = await setupTest() did = await didRegistry.hashDID(didSeed, artist) - await didRegistry.registerMintableDID( - didSeed, checksum, [], url, cappedAmount, royalties, constants.activities.GENERATED, '', { from: artist }) + await didRegistry.registerMintableDID721( + didSeed, checksum, [], url, royalties, true, constants.activities.GENERATED, '', { from: artist }) - await nft.mint(artist, did, url, { from: owner }) await nft.setApprovalForAll(transferCondition.address, true, { from: artist }) }) }) diff --git a/test/unit/registry/Mintable721DIDRegistry.js b/test/unit/registry/Mintable721DIDRegistry.js index 5a1912e1..71aeb639 100644 --- a/test/unit/registry/Mintable721DIDRegistry.js +++ b/test/unit/registry/Mintable721DIDRegistry.js @@ -17,6 +17,7 @@ contract('Mintable DIDRegistry (ERC-721)', (accounts) => { const other = accounts[2] const consumer = accounts[3] const value = 'https://nevermined.io/did/nevermined/test-attr-example.txt' + const nftMetadataURL = 'https://nevermined.io/metadata.json' let didRegistry let didRegistryLibrary let didRegistryLibraryProxy @@ -100,18 +101,49 @@ contract('Mintable DIDRegistry (ERC-721)', (accounts) => { await didRegistry.registerAttribute( didSeed, checksum, [], value, { from: owner }) - await didRegistry.enableAndMintDidNft721(did, 0, true, { from: owner }) + await didRegistry.enableAndMintDidNft721(did, 0, true, nftMetadataURL, { from: owner }) const nftOwner = await nft.ownerOf(did) assert.strictEqual(owner, nftOwner) - await didRegistry.burn721(did, - { - from: owner - } - ) - + await didRegistry.burn721(did, { from: owner }) await assert.isRejected(nft.ownerOf(did)) + + const _nftURI = await nft.tokenURI(did) + assert.strictEqual(nftMetadataURL, _nftURI) + }) + + it('Should work with an empty NFT Metadata URL', async () => { + const didSeed = testUtils.generateId() + const did = await didRegistry.hashDID(didSeed, owner) + const checksum = testUtils.generateId() + + await didRegistry.registerAttribute( + didSeed, checksum, [], value, { from: owner }) + await didRegistry.enableAndMintDidNft721(did, 0, true, '', { from: owner }) + + const nftOwner = await nft.ownerOf(did) + assert.strictEqual(owner, nftOwner) + + const _nftURI = await nft.tokenURI(did) + assert.strictEqual('', _nftURI) + }) + + it('The royalties should be initialized and retrieved (ERC-2981)', async () => { + const didSeed = testUtils.generateId() + const did = await didRegistry.hashDID(didSeed, owner) + const checksum = testUtils.generateId() + await didRegistry.registerAttribute( + didSeed, checksum, [], value, { from: owner }) + + await didRegistry.enableAndMintDidNft721(did, 10, true, nftMetadataURL, { from: owner }) + + const nftOwner = await nft.ownerOf(did) + assert.strictEqual(owner, nftOwner) + + const { receiver, royaltyAmount } = await nft.royaltyInfo(did, 500) + assert.strictEqual(owner, receiver) + assert.strictEqual(50, royaltyAmount.toNumber()) }) it('Should Mint automatically if is configured that way', async () => { @@ -121,7 +153,7 @@ contract('Mintable DIDRegistry (ERC-721)', (accounts) => { await didRegistry.registerAttribute( didSeed, checksum, [], value, { from: owner }) - await didRegistry.enableAndMintDidNft721(did, 0, true, { from: owner }) + await didRegistry.enableAndMintDidNft721(did, 0, true, nftMetadataURL, { from: owner }) const nftOwner = await nft.ownerOf(did) assert.strictEqual(owner, nftOwner) @@ -134,7 +166,7 @@ contract('Mintable DIDRegistry (ERC-721)', (accounts) => { await didRegistry.registerAttribute( didSeed, checksum, [], value, { from: owner }) - await didRegistry.enableAndMintDidNft721(did, 0, false, { from: owner }) + await didRegistry.enableAndMintDidNft721(did, 0, false, nftMetadataURL, { from: owner }) await assert.isRejected(nft.ownerOf(did)) @@ -150,7 +182,7 @@ contract('Mintable DIDRegistry (ERC-721)', (accounts) => { const checksum = testUtils.generateId() await didRegistry.registerAttribute( didSeed, checksum, [], value, { from: owner }) - await didRegistry.enableAndMintDidNft721(did, 0, false, { from: owner }) + await didRegistry.enableAndMintDidNft721(did, 0, false, nftMetadataURL, { from: owner }) await didRegistry.mint721(did, { from: owner }) let nftOwner = await nft.ownerOf(did) @@ -173,11 +205,11 @@ contract('Mintable DIDRegistry (ERC-721)', (accounts) => { await assert.isRejected( // Must not allow to initialize NFTs if not the owner - didRegistry.enableAndMintDidNft721(did, 0, true, { from: other }), + didRegistry.enableAndMintDidNft721(did, 0, true, nftMetadataURL, { from: other }), 'Only owner' ) - await didRegistry.enableAndMintDidNft721(did, 0, true, { from: owner }) + await didRegistry.enableAndMintDidNft721(did, 0, true, nftMetadataURL, { from: owner }) await assert.isRejected( // Must not allow to mint tokens without previous initialization didRegistry.mint721(did, { from: other }), diff --git a/test/unit/registry/MintableDIDRegistry.js b/test/unit/registry/MintableDIDRegistry.js index fc0bb203..1ef068ee 100644 --- a/test/unit/registry/MintableDIDRegistry.js +++ b/test/unit/registry/MintableDIDRegistry.js @@ -17,6 +17,7 @@ contract('Mintable DIDRegistry', (accounts) => { const other = accounts[2] const consumer = accounts[3] const value = 'https://nevermined.io/did/nevermined/test-attr-example.txt' + const nftMetadataURL = 'https://nevermined.io/metadata.json' let didRegistry let didRegistryLibrary let didRegistryLibraryProxy @@ -100,7 +101,7 @@ contract('Mintable DIDRegistry', (accounts) => { const checksum = testUtils.generateId() await didRegistry.registerMintableDID( - didSeed, checksum, [], value, 20, 0, constants.activities.GENERATED, '', { from: owner }) + didSeed, checksum, [], value, 20, 0, constants.activities.GENERATED, nftMetadataURL, { from: owner }) await didRegistry.mint(did, 20, { from: owner }) let balance = await nft.balanceOf(owner, did) @@ -114,6 +115,9 @@ contract('Mintable DIDRegistry', (accounts) => { balance = await nft.balanceOf(owner, did) assert.strictEqual(15, balance.toNumber()) + + const _nftURI = await nft.uri(did) + assert.strictEqual(nftMetadataURL, _nftURI) }) it('Should initialize the NFT in the registration', async () => { @@ -128,6 +132,18 @@ contract('Mintable DIDRegistry', (accounts) => { assert.strictEqual(10, balance.toNumber()) }) + it('The royalties should be initialized and retrieved (ERC-2981)', async () => { + const didSeed = testUtils.generateId() + const did = await didRegistry.hashDID(didSeed, owner) + const checksum = testUtils.generateId() + await didRegistry.registerMintableDID( + didSeed, checksum, [], value, 999, 10, constants.activities.GENERATED, '', { from: owner }) + + const { receiver, royaltyAmount } = await nft.royaltyInfo(did, 500) + assert.strictEqual(owner, receiver) + assert.strictEqual(50, royaltyAmount.toNumber()) + }) + it('Should Mint automatically if is configured that way', async () => { const didSeed = testUtils.generateId() const did = await didRegistry.hashDID(didSeed, owner) @@ -135,7 +151,7 @@ contract('Mintable DIDRegistry', (accounts) => { await didRegistry.registerAttribute( didSeed, checksum, [], value, { from: owner }) - await didRegistry.enableAndMintDidNft(did, 5, 0, true, { from: owner }) + await didRegistry.enableAndMintDidNft(did, 5, 0, true, nftMetadataURL, { from: owner }) const balanceOwner = await nft.balanceOf(owner, did) assert.strictEqual(5, balanceOwner.toNumber()) @@ -188,11 +204,11 @@ contract('Mintable DIDRegistry', (accounts) => { await assert.isRejected( // Must not allow to initialize NFTs if not the owner - didRegistry.enableAndMintDidNft(did, 5, 0, true, { from: other }), + didRegistry.enableAndMintDidNft(did, 5, 0, true, nftMetadataURL, { from: other }), 'Only owner' ) - await didRegistry.enableAndMintDidNft(did, 5, 0, true, { from: owner }) + await didRegistry.enableAndMintDidNft(did, 5, 0, true, nftMetadataURL, { from: owner }) await assert.isRejected( // Must not allow to mint tokens without previous initialization didRegistry.mint(did, 1, { from: other }),