diff --git a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol index 70fc8a5d..dc0dcc12 100644 --- a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol +++ b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol @@ -105,6 +105,16 @@ interface IERC7508 is IERC165 { address specificAddress ); + /** + * @notice Used to notify listeners that the metadata URI for a collection has been updated. + * @param collection Address of the collection + * @param attributesMetadataURI The new attributes metadata URI + */ + event MetadataURIUpdated( + address indexed collection, + string attributesMetadataURI + ); + /** * @notice Used to notify listeners that a new collaborator has been added or removed. * @param collection Address of the collection @@ -244,6 +254,26 @@ interface IERC7508 is IERC165 { bool[] memory collaboratorAddressAccess ) external; + /** + * @notice Used to retrieve the attributes metadata URI for a collection, which contains all the information about the collection attributes. + * @param collection Address of the collection + * @return attributesMetadataURI The URI of the attributes metadata + */ + function getAttributesMetadataURI( + address collection + ) external view returns (string memory attributesMetadataURI); + + /** + * @notice Used to set the metadata URI for a collection, which contains all the information about the collection attributes. + * @dev Emits a {MetadataURIUpdated} event. + * @param collection Address of the collection + * @param attributesMetadataURI The URI of the attributes metadata + */ + function setAttributesMetadataURI( + address collection, + string memory attributesMetadataURI + ) external; + /** * @notice Used to set a number attribute. * @dev Emits a {UintAttributeUpdated} event. @@ -326,13 +356,13 @@ interface IERC7508 is IERC165 { * string key, * string value * ] - * @param collection Address of the collection - * @param tokenId ID of the token + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. * @param attributes An array of `StringAttribute` structs to be assigned to the given token */ function setStringAttributes( - address collection, - uint256 tokenId, + address[] memory collections, + uint256[] memory tokenIds, StringAttribute[] memory attributes ) external; @@ -343,13 +373,13 @@ interface IERC7508 is IERC165 { * string key, * uint value * ] - * @param collection Address of the collection - * @param tokenId ID of the token + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. * @param attributes An array of `UintAttribute` structs to be assigned to the given token */ function setUintAttributes( - address collection, - uint256 tokenId, + address[] memory collections, + uint256[] memory tokenIds, UintAttribute[] memory attributes ) external; @@ -360,13 +390,13 @@ interface IERC7508 is IERC165 { * string key, * bool value * ] - * @param collection Address of the collection - * @param tokenId ID of the token + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. * @param attributes An array of `BoolAttribute` structs to be assigned to the given token */ function setBoolAttributes( - address collection, - uint256 tokenId, + address[] memory collections, + uint256[] memory tokenIds, BoolAttribute[] memory attributes ) external; @@ -377,13 +407,13 @@ interface IERC7508 is IERC165 { * string key, * address value * ] - * @param collection Address of the collection - * @param tokenId ID of the token + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. * @param attributes An array of `AddressAttribute` structs to be assigned to the given token */ function setAddressAttributes( - address collection, - uint256 tokenId, + address[] memory collections, + uint256[] memory tokenIds, AddressAttribute[] memory attributes ) external; @@ -394,13 +424,13 @@ interface IERC7508 is IERC165 { * string key, * bytes value * ] - * @param collection Address of the collection - * @param tokenId ID of the token + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. * @param attributes An array of `BytesAttribute` structs to be assigned to the given token */ function setBytesAttributes( - address collection, - uint256 tokenId, + address[] memory collections, + uint256[] memory tokenIds, BytesAttribute[] memory attributes ) external; @@ -748,11 +778,11 @@ interface IERC7508 is IERC165 { * @param boolKeys An array of bool type attribute keys to retrieve * @param addressKeys An array of address type attribute keys to retrieve * @param bytesKeys An array of bytes type attribute keys to retrieve - * @return stringAttributes An array of `StringAttribute` structs containing the string type attributes - * @return uintAttributes An array of `UintAttribute` structs containing the uint type attributes - * @return boolAttributes An array of `BoolAttribute` structs containing the bool type attributes - * @return addressAttributes An array of `AddressAttribute` structs containing the address type attributes - * @return bytesAttributes An array of `BytesAttribute` structs containing the bytes type attributes + * @return stringAttributes An array of strings, in the same order as the stringKeys + * @return uintAttributes An array of uints, in the same order as the uintKeys + * @return boolAttributes An array of bools, in the same order as the boolKeys + * @return addressAttributes An array of addresses, in the same order as the addressKeys + * @return bytesAttributes An array of bytes, in the same order as the bytesKeys */ function getAttributes( address collection, @@ -766,11 +796,11 @@ interface IERC7508 is IERC165 { external view returns ( - StringAttribute[] memory stringAttributes, - UintAttribute[] memory uintAttributes, - BoolAttribute[] memory boolAttributes, - AddressAttribute[] memory addressAttributes, - BytesAttribute[] memory bytesAttributes + string[] memory stringAttributes, + uint256[] memory uintAttributes, + bool[] memory boolAttributes, + address[] memory addressAttributes, + bytes[] memory bytesAttributes ); /** @@ -780,16 +810,16 @@ interface IERC7508 is IERC165 { * string key, * string value * ] - * @param collection Address of the collection the token belongs to - * @param tokenId ID of the token for which the attributes are being retrieved - * @param stringKeys An array of string keys to retrieve - * @return attributes An array of `StringAttribute` structs + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of string keys to retrieve + * @return attributes An array of strings, in the same order as the attribute keys */ function getStringAttributes( - address collection, - uint256 tokenId, - string[] memory stringKeys - ) external view returns (StringAttribute[] memory attributes); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) external view returns (string[] memory attributes); /** * @notice Used to get multiple uint parameter values for a token. @@ -798,16 +828,16 @@ interface IERC7508 is IERC165 { * string key, * uint value * ] - * @param collection Address of the collection the token belongs to - * @param tokenId ID of the token for which the attributes are being retrieved - * @param uintKeys An array of uint keys to retrieve - * @return attributes An array of `UintAttribute` structs + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of uint keys to retrieve + * @return attributes An array of uints, in the same order as the attribute keys */ function getUintAttributes( - address collection, - uint256 tokenId, - string[] memory uintKeys - ) external view returns (UintAttribute[] memory attributes); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) external view returns (uint256[] memory attributes); /** * @notice Used to get multiple bool parameter values for a token. @@ -816,16 +846,16 @@ interface IERC7508 is IERC165 { * string key, * bool value * ] - * @param collection Address of the collection the token belongs to - * @param tokenId ID of the token for which the attributes are being retrieved - * @param boolKeys An array of bool keys to retrieve - * @return attributes An array of `BoolAttribute` structs + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of bool keys to retrieve + * @return attributes An array of bools, in the same order as the attribute keys */ function getBoolAttributes( - address collection, - uint256 tokenId, - string[] memory boolKeys - ) external view returns (BoolAttribute[] memory attributes); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) external view returns (bool[] memory attributes); /** * @notice Used to get multiple address parameter values for a token. @@ -834,16 +864,16 @@ interface IERC7508 is IERC165 { * string key, * address value * ] - * @param collection Address of the collection the token belongs to - * @param tokenId ID of the token for which the attributes are being retrieved - * @param addressKeys An array of address keys to retrieve - * @return attributes An array of `AddressAttribute` structs + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of address keys to retrieve + * @return attributes An array of addresses, in the same order as the attribute keys */ function getAddressAttributes( - address collection, - uint256 tokenId, - string[] memory addressKeys - ) external view returns (AddressAttribute[] memory attributes); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) external view returns (address[] memory attributes); /** * @notice Used to get multiple bytes parameter values for a token. @@ -852,14 +882,14 @@ interface IERC7508 is IERC165 { * string key, * bytes value * ] - * @param collection Address of the collection the token belongs to - * @param tokenId ID of the token for which the attributes are being retrieved - * @param bytesKeys An array of bytes keys to retrieve - * @return attributes An array of `BytesAttribute` structs + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of bytes keys to retrieve + * @return attributes An array of bytes, in the same order as the attribute keys */ function getBytesAttributes( - address collection, - uint256 tokenId, - string[] memory bytesKeys - ) external view returns (BytesAttribute[] memory attributes); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) external view returns (bytes[] memory attributes); } diff --git a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol index a31bef1f..f1711765 100644 --- a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol +++ b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol @@ -44,35 +44,32 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { "setAddressAttribute(address collection,uint256 tokenId,string memory key,address value)" ); - mapping(address => mapping(uint256 => AccessType)) + mapping(address collection => mapping(uint256 parameterId => AccessType accessType)) private _parameterAccessType; - mapping(address => mapping(uint256 => address)) + mapping(address collection => mapping(uint256 parameterId => address specificAddress)) private _parameterSpecificAddress; - mapping(address => IssuerSetting) private _issuerSettings; - mapping(address => mapping(address => bool)) private _collaborators; + mapping(address collection => IssuerSetting setting) + private _issuerSettings; + mapping(address collection => mapping(address collaborator => bool isCollaborator)) + private _collaborators; // For keys, we use a mapping from strings to IDs. // The purpose is to store unique string keys only once, since they are more expensive. - mapping(string => uint256) private _keysToIds; - uint256 private _totalAttributes; - - // For strings, we also use a mapping from strings to IDs, together with a reverse mapping - // The purpose is to store unique string values only once, since they are more expensive, - // and storing only IDs. - mapping(address => uint256) private _totalStringValues; - mapping(address => mapping(string => uint256)) private _stringValueToId; - mapping(address => mapping(uint256 => string)) private _stringIdToValue; - mapping(address => mapping(uint256 => mapping(uint256 => uint256))) - private _stringValueIds; - - mapping(address => mapping(uint256 => mapping(uint256 => address))) + mapping(string key => uint256 id) private _keysToIds; + uint256 private _nextKeyId; + + mapping(address collection => string attributesMetadataURI) + private _attributesMetadataURIs; + mapping(address collection => mapping(uint256 => mapping(uint256 => address))) private _addressValues; - mapping(address => mapping(uint256 => mapping(uint256 => bytes))) + mapping(address collection => mapping(uint256 => mapping(uint256 => bytes))) private _bytesValues; - mapping(address => mapping(uint256 => mapping(uint256 => uint256))) + mapping(address collection => mapping(uint256 => mapping(uint256 => uint256))) private _uintValues; - mapping(address => mapping(uint256 => mapping(uint256 => bool))) + mapping(address collection => mapping(uint256 => mapping(uint256 => bool))) private _boolValues; + mapping(address collection => mapping(uint256 => mapping(uint256 => string))) + private _stringValues; struct IssuerSetting { bool registered; @@ -80,6 +77,8 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address issuer; } + /// Used to signal that the length of the arrays is not equal. + error LengthsMismatch(); /// Used to signal that the smart contract interacting with the repository does not implement Ownable pattern. error OwnableNotImplemented(); /// Used to signal that the caller is not the issuer of the collection. @@ -88,8 +87,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { error CollaboratorArraysNotEqualLength(); /// Used to signal that the collection is not registered in the repository yet. error CollectionNotRegistered(); - /// Used to signal that the collection is already registered in the repository. - error CollectionAlreadyRegistered(); /// Used to signal that the caller is not aa collaborator of the collection. error NotCollectionCollaborator(); /// Used to signal that the caller is not the issuer or a collaborator of the collection. @@ -110,7 +107,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address collection, address issuer, bool useOwnable - ) external onlyUnregisteredCollection(collection) { + ) external { (bool ownableSuccess, bytes memory ownableReturn) = collection.call( abi.encodeWithSignature("owner()") ); @@ -125,10 +122,11 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { revert NotCollectionIssuer(); } - IssuerSetting storage issuerSetting = _issuerSettings[collection]; - issuerSetting.registered = true; - issuerSetting.issuer = issuer; - issuerSetting.useOwnable = useOwnable; + _issuerSettings[collection] = IssuerSetting({ + registered: true, + issuer: issuer, + useOwnable: useOwnable + }); emit AccessControlRegistration( collection, @@ -182,6 +180,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } } + /** + * @inheritdoc IERC7508 + */ + function getAttributesMetadataURI( + address collection + ) external view returns (string memory attributesMetadataURI) { + attributesMetadataURI = _attributesMetadataURIs[collection]; + } + + /** + * @inheritdoc IERC7508 + */ + function setAttributesMetadataURI( + address collection, + string memory attributesMetadataURI + ) external onlyIssuer(collection) { + _attributesMetadataURIs[collection] = attributesMetadataURI; + emit MetadataURIUpdated(collection, attributesMetadataURI); + } + /** * @inheritdoc IERC7508 */ @@ -235,17 +253,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { _; } - /** - * @notice Modifier to check if the collection is not registered. - * @param collection Address of the collection. - */ - modifier onlyUnregisteredCollection(address collection) { - if (_issuerSettings[collection].registered) { - revert CollectionAlreadyRegistered(); - } - _; - } - /** * @notice Modifier to check if the caller is the issuer of the collection. * @param collection Address of the collection. @@ -319,11 +326,8 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address collection, uint256 tokenId, string memory key - ) external view returns (string memory attribute) { - uint256 idForValue = _stringValueIds[collection][tokenId][ - _keysToIds[key] - ]; - attribute = _stringIdToValue[collection][idForValue]; + ) public view returns (string memory attribute) { + attribute = _stringValues[collection][tokenId][_keysToIds[key]]; } /** @@ -333,7 +337,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address collection, uint256 tokenId, string memory key - ) external view returns (uint256 attribute) { + ) public view returns (uint256 attribute) { attribute = _uintValues[collection][tokenId][_keysToIds[key]]; } @@ -344,7 +348,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address collection, uint256 tokenId, string memory key - ) external view returns (bool attribute) { + ) public view returns (bool attribute) { attribute = _boolValues[collection][tokenId][_keysToIds[key]]; } @@ -355,7 +359,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address collection, uint256 tokenId, string memory key - ) external view returns (address attribute) { + ) public view returns (address attribute) { attribute = _addressValues[collection][tokenId][_keysToIds[key]]; } @@ -366,7 +370,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address collection, uint256 tokenId, string memory key - ) external view returns (bytes memory attribute) { + ) public view returns (bytes memory attribute) { attribute = _bytesValues[collection][tokenId][_keysToIds[key]]; } @@ -385,49 +389,60 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { external view returns ( - StringAttribute[] memory stringAttributes, - UintAttribute[] memory uintAttributes, - BoolAttribute[] memory boolAttributes, - AddressAttribute[] memory addressAttributes, - BytesAttribute[] memory bytesAttributes + string[] memory stringAttributes, + uint256[] memory uintAttributes, + bool[] memory boolAttributes, + address[] memory addressAttributes, + bytes[] memory bytesAttributes ) { - stringAttributes = getStringAttributes(collection, tokenId, stringKeys); - - uintAttributes = getUintAttributes(collection, tokenId, uintKeys); - - boolAttributes = getBoolAttributes(collection, tokenId, boolKeys); - + address[] memory collections = new address[](1); + uint256[] memory tokenIds = new uint256[](1); + collections[0] = collection; + tokenIds[0] = tokenId; + + stringAttributes = getStringAttributes( + collections, + tokenIds, + stringKeys + ); + uintAttributes = getUintAttributes(collections, tokenIds, uintKeys); + boolAttributes = getBoolAttributes(collections, tokenIds, boolKeys); addressAttributes = getAddressAttributes( - collection, - tokenId, + collections, + tokenIds, addressKeys ); - - bytesAttributes = getBytesAttributes(collection, tokenId, bytesKeys); + bytesAttributes = getBytesAttributes(collections, tokenIds, bytesKeys); } /** * @inheritdoc IERC7508 */ function getStringAttributes( - address collection, - uint256 tokenId, - string[] memory stringKeys - ) public view returns (StringAttribute[] memory attributes) { - uint256 stringLen = stringKeys.length; - - attributes = new StringAttribute[](stringLen); - - for (uint256 i; i < stringLen; ) { - attributes[i] = StringAttribute({ - key: stringKeys[i], - value: _stringIdToValue[collection][ - _stringValueIds[collection][tokenId][ - _keysToIds[stringKeys[i]] - ] - ] - }); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) public view returns (string[] memory attributes) { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); + + attributes = new string[](loopLength); + + for (uint256 i; i < loopLength; ) { + attributes[i] = getStringAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + multipleAttributes ? attributeKeys[i] : attributeKeys[0] + ); unchecked { ++i; } @@ -438,19 +453,29 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getUintAttributes( - address collection, - uint256 tokenId, - string[] memory uintKeys - ) public view returns (UintAttribute[] memory attributes) { - uint256 uintLen = uintKeys.length; + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) public view returns (uint256[] memory attributes) { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); - attributes = new UintAttribute[](uintLen); + attributes = new uint256[](loopLength); - for (uint256 i; i < uintLen; ) { - attributes[i] = UintAttribute({ - key: uintKeys[i], - value: _uintValues[collection][tokenId][_keysToIds[uintKeys[i]]] - }); + for (uint256 i; i < loopLength; ) { + attributes[i] = getUintAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + multipleAttributes ? attributeKeys[i] : attributeKeys[0] + ); unchecked { ++i; } @@ -461,19 +486,29 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getBoolAttributes( - address collection, - uint256 tokenId, - string[] memory boolKeys - ) public view returns (BoolAttribute[] memory attributes) { - uint256 boolLen = boolKeys.length; + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) public view returns (bool[] memory attributes) { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); - attributes = new BoolAttribute[](boolLen); + attributes = new bool[](loopLength); - for (uint256 i; i < boolLen; ) { - attributes[i] = BoolAttribute({ - key: boolKeys[i], - value: _boolValues[collection][tokenId][_keysToIds[boolKeys[i]]] - }); + for (uint256 i; i < loopLength; ) { + attributes[i] = getBoolAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + multipleAttributes ? attributeKeys[i] : attributeKeys[0] + ); unchecked { ++i; } @@ -484,20 +519,29 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getAddressAttributes( - address collection, - uint256 tokenId, - string[] memory addressKeys - ) public view returns (AddressAttribute[] memory attributes) { - uint256 addressLen = addressKeys.length; - attributes = new AddressAttribute[](addressLen); - - for (uint256 i; i < addressLen; ) { - attributes[i] = AddressAttribute({ - key: addressKeys[i], - value: _addressValues[collection][tokenId][ - _keysToIds[addressKeys[i]] - ] - }); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) public view returns (address[] memory attributes) { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); + + attributes = new address[](loopLength); + + for (uint256 i; i < loopLength; ) { + attributes[i] = getAddressAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + multipleAttributes ? attributeKeys[i] : attributeKeys[0] + ); unchecked { ++i; } @@ -508,20 +552,29 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getBytesAttributes( - address collection, - uint256 tokenId, - string[] memory bytesKeys - ) public view returns (BytesAttribute[] memory attributes) { - uint256 bytesLen = bytesKeys.length; - attributes = new BytesAttribute[](bytesLen); - - for (uint256 i; i < bytesLen; ) { - attributes[i] = BytesAttribute({ - key: bytesKeys[i], - value: _bytesValues[collection][tokenId][ - _keysToIds[bytesKeys[i]] - ] - }); + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) public view returns (bytes[] memory attributes) { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); + + attributes = new bytes[](loopLength); + + for (uint256 i; i < loopLength; ) { + attributes[i] = getBytesAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + multipleAttributes ? attributeKeys[i] : attributeKeys[0] + ); unchecked { ++i; } @@ -646,88 +699,91 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setUintAttribute( + function setBoolAttribute( address collection, uint256 tokenId, string memory key, - uint256 value - ) external onlyAuthorizedCaller(collection, key, tokenId) { - _uintValues[collection][tokenId][_getIdForKey(key)] = value; - emit UintAttributeUpdated(collection, tokenId, key, value); + bool value + ) external { + _setBoolAttribute(_msgSender(), collection, tokenId, key, value); } /** * @inheritdoc IERC7508 */ - function setStringAttribute( + function setBytesAttribute( address collection, uint256 tokenId, string memory key, - string memory value - ) external onlyAuthorizedCaller(collection, key, tokenId) { - _stringValueIds[collection][tokenId][ - _getIdForKey(key) - ] = _getStringIdForValue(collection, value); - emit StringAttributeUpdated(collection, tokenId, key, value); + bytes memory value + ) external { + _setBytesAttribute(_msgSender(), collection, tokenId, key, value); } /** * @inheritdoc IERC7508 */ - function setBoolAttribute( + function setAddressAttribute( address collection, uint256 tokenId, string memory key, - bool value - ) external onlyAuthorizedCaller(collection, key, tokenId) { - _boolValues[collection][tokenId][_getIdForKey(key)] = value; - emit BoolAttributeUpdated(collection, tokenId, key, value); + address value + ) external { + _setAddressAttribute(_msgSender(), collection, tokenId, key, value); } /** * @inheritdoc IERC7508 */ - function setBytesAttribute( + function setUintAttribute( address collection, uint256 tokenId, string memory key, - bytes memory value - ) external onlyAuthorizedCaller(collection, key, tokenId) { - _bytesValues[collection][tokenId][_getIdForKey(key)] = value; - emit BytesAttributeUpdated(collection, tokenId, key, value); + uint256 value + ) external { + _setUintAttribute(_msgSender(), collection, tokenId, key, value); } /** * @inheritdoc IERC7508 */ - function setAddressAttribute( + function setStringAttribute( address collection, uint256 tokenId, string memory key, - address value - ) external onlyAuthorizedCaller(collection, key, tokenId) { - _addressValues[collection][tokenId][_getIdForKey(key)] = value; - emit AddressAttributeUpdated(collection, tokenId, key, value); + string memory value + ) external { + _setStringAttribute(_msgSender(), collection, tokenId, key, value); } /** * @inheritdoc IERC7508 */ - function setStringAttributes( - address collection, - uint256 tokenId, - StringAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { - uint256 length = attributes.length; - for (uint256 i = 0; i < length; ) { - _stringValueIds[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = _getStringIdForValue(collection, attributes[i].value); - emit StringAttributeUpdated( - collection, - tokenId, - attributes[i].key, - attributes[i].value + function setBoolAttributes( + address[] memory collections, + uint256[] memory tokenIds, + BoolAttribute[] memory attributes + ) external { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributes.length + ); + for (uint256 i; i < loopLength; ) { + BoolAttribute memory attribute = multipleAttributes + ? attributes[i] + : attributes[0]; + _setBoolAttribute( + _msgSender(), + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -738,21 +794,31 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setUintAttributes( - address collection, - uint256 tokenId, - UintAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { - uint256 length = attributes.length; - for (uint256 i = 0; i < length; ) { - _uintValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit UintAttributeUpdated( - collection, - tokenId, - attributes[i].key, - attributes[i].value + function setBytesAttributes( + address[] memory collections, + uint256[] memory tokenIds, + BytesAttribute[] memory attributes + ) external { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributes.length + ); + for (uint256 i; i < loopLength; ) { + BytesAttribute memory attribute = multipleAttributes + ? attributes[i] + : attributes[0]; + _setBytesAttribute( + _msgSender(), + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -763,21 +829,31 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setBoolAttributes( - address collection, - uint256 tokenId, - BoolAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { - uint256 length = attributes.length; - for (uint256 i = 0; i < length; ) { - _boolValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit BoolAttributeUpdated( - collection, - tokenId, - attributes[i].key, - attributes[i].value + function setStringAttributes( + address[] memory collections, + uint256[] memory tokenIds, + StringAttribute[] memory attributes + ) external { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributes.length + ); + for (uint256 i; i < loopLength; ) { + StringAttribute memory attribute = multipleAttributes + ? attributes[i] + : attributes[0]; + _setStringAttribute( + _msgSender(), + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -788,21 +864,31 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setAddressAttributes( - address collection, - uint256 tokenId, - AddressAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { - uint256 length = attributes.length; - for (uint256 i = 0; i < length; ) { - _addressValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit AddressAttributeUpdated( - collection, - tokenId, - attributes[i].key, - attributes[i].value + function setUintAttributes( + address[] memory collections, + uint256[] memory tokenIds, + UintAttribute[] memory attributes + ) external { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributes.length + ); + for (uint256 i; i < loopLength; ) { + UintAttribute memory attribute = multipleAttributes + ? attributes[i] + : attributes[0]; + _setUintAttribute( + _msgSender(), + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -813,21 +899,31 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setBytesAttributes( - address collection, - uint256 tokenId, - BytesAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { - uint256 length = attributes.length; - for (uint256 i = 0; i < length; ) { - _bytesValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit BytesAttributeUpdated( - collection, - tokenId, - attributes[i].key, - attributes[i].value + function setAddressAttributes( + address[] memory collections, + uint256[] memory tokenIds, + AddressAttribute[] memory attributes + ) external { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributes.length + ); + for (uint256 i; i < loopLength; ) { + AddressAttribute memory attribute = multipleAttributes + ? attributes[i] + : attributes[0]; + _setAddressAttribute( + _msgSender(), + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -846,13 +942,11 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { BoolAttribute[] memory boolAttributes, AddressAttribute[] memory addressAttributes, BytesAttribute[] memory bytesAttributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { + ) external { uint256 length = stringAttributes.length; - for (uint256 i = 0; i < length; ) { - _stringValueIds[collection][tokenId][ - _getIdForKey(stringAttributes[i].key) - ] = _getStringIdForValue(collection, stringAttributes[i].value); - emit StringAttributeUpdated( + for (uint256 i; i < length; ) { + _setStringAttribute( + _msgSender(), collection, tokenId, stringAttributes[i].key, @@ -864,11 +958,9 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = uintAttributes.length; - for (uint256 i = 0; i < length; ) { - _uintValues[collection][tokenId][ - _getIdForKey(uintAttributes[i].key) - ] = uintAttributes[i].value; - emit UintAttributeUpdated( + for (uint256 i; i < length; ) { + _setUintAttribute( + _msgSender(), collection, tokenId, uintAttributes[i].key, @@ -880,11 +972,9 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = boolAttributes.length; - for (uint256 i = 0; i < length; ) { - _boolValues[collection][tokenId][ - _getIdForKey(boolAttributes[i].key) - ] = boolAttributes[i].value; - emit BoolAttributeUpdated( + for (uint256 i; i < length; ) { + _setBoolAttribute( + _msgSender(), collection, tokenId, boolAttributes[i].key, @@ -896,11 +986,9 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = addressAttributes.length; - for (uint256 i = 0; i < length; ) { - _addressValues[collection][tokenId][ - _getIdForKey(addressAttributes[i].key) - ] = addressAttributes[i].value; - emit AddressAttributeUpdated( + for (uint256 i; i < length; ) { + _setAddressAttribute( + _msgSender(), collection, tokenId, addressAttributes[i].key, @@ -912,11 +1000,9 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = bytesAttributes.length; - for (uint256 i = 0; i < length; ) { - _bytesValues[collection][tokenId][ - _getIdForKey(bytesAttributes[i].key) - ] = bytesAttributes[i].value; - emit BytesAttributeUpdated( + for (uint256 i; i < length; ) { + _setBytesAttribute( + _msgSender(), collection, tokenId, bytesAttributes[i].key, @@ -928,6 +1014,106 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } } + function _checkIfMultipleCollectionsAndTokens( + address[] memory collections, + uint256[] memory tokenIds, + uint256 attributesLength + ) + internal + pure + returns ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) + { + multipleCollections = collections.length != 1; + multipleTokens = tokenIds.length != 1; + multipleAttributes = attributesLength != 1; + if ( + (multipleCollections && + multipleAttributes && + collections.length != attributesLength) || + (multipleTokens && + multipleAttributes && + tokenIds.length != attributesLength) || + (multipleCollections && + multipleTokens && + collections.length != tokenIds.length) + ) { + revert LengthsMismatch(); + } + + if (multipleCollections) { + loopLength = collections.length; + } else if (multipleTokens) { + loopLength = tokenIds.length; + } else { + loopLength = attributesLength; + } + } + + function _setBoolAttribute( + address caller, + address collection, + uint256 tokenId, + string memory key, + bool value + ) internal { + _onlyAuthorizedCaller(caller, collection, key, tokenId); + _boolValues[collection][tokenId][_getIdForKey(key)] = value; + emit BoolAttributeUpdated(collection, tokenId, key, value); + } + + function _setBytesAttribute( + address caller, + address collection, + uint256 tokenId, + string memory key, + bytes memory value + ) internal { + _onlyAuthorizedCaller(caller, collection, key, tokenId); + _bytesValues[collection][tokenId][_getIdForKey(key)] = value; + emit BytesAttributeUpdated(collection, tokenId, key, value); + } + + function _setAddressAttribute( + address caller, + address collection, + uint256 tokenId, + string memory key, + address value + ) internal { + _onlyAuthorizedCaller(caller, collection, key, tokenId); + _addressValues[collection][tokenId][_getIdForKey(key)] = value; + emit AddressAttributeUpdated(collection, tokenId, key, value); + } + + function _setStringAttribute( + address caller, + address collection, + uint256 tokenId, + string memory key, + string memory value + ) internal { + _onlyAuthorizedCaller(caller, collection, key, tokenId); + _stringValues[collection][tokenId][_getIdForKey(key)] = value; + emit StringAttributeUpdated(collection, tokenId, key, value); + } + + function _setUintAttribute( + address caller, + address collection, + uint256 tokenId, + string memory key, + uint256 value + ) internal { + _onlyAuthorizedCaller(caller, collection, key, tokenId); + _uintValues[collection][tokenId][_getIdForKey(key)] = value; + emit UintAttributeUpdated(collection, tokenId, key, value); + } + /** * @inheritdoc IERC7508 */ @@ -942,10 +1128,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { bytes32 r, bytes32 s ) external { - if (block.timestamp > deadline) { - revert ExpiredDeadline(); - } - bytes32 digest = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", @@ -962,14 +1144,8 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { ) ) ); - address signer = ecrecover(digest, v, r, s); - if (signer != setter) { - revert InvalidSignature(); - } - _onlyAuthorizedCaller(signer, collection, key, tokenId); - - _uintValues[collection][tokenId][_getIdForKey(key)] = value; - emit UintAttributeUpdated(collection, tokenId, key, value); + _checkDeadlineAndSigner(setter, deadline, digest, v, r, s); + _setUintAttribute(setter, collection, tokenId, key, value); } /** @@ -986,10 +1162,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { bytes32 r, bytes32 s ) external { - if (block.timestamp > deadline) { - revert ExpiredDeadline(); - } - bytes32 digest = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", @@ -1006,16 +1178,8 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { ) ) ); - address signer = ecrecover(digest, v, r, s); - if (signer != setter) { - revert InvalidSignature(); - } - _onlyAuthorizedCaller(signer, collection, key, tokenId); - - _stringValueIds[collection][tokenId][ - _getIdForKey(key) - ] = _getStringIdForValue(collection, value); - emit StringAttributeUpdated(collection, tokenId, key, value); + _checkDeadlineAndSigner(setter, deadline, digest, v, r, s); + _setStringAttribute(setter, collection, tokenId, key, value); } /** @@ -1032,10 +1196,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { bytes32 r, bytes32 s ) external { - if (block.timestamp > deadline) { - revert ExpiredDeadline(); - } - bytes32 digest = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", @@ -1052,14 +1212,8 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { ) ) ); - address signer = ecrecover(digest, v, r, s); - if (signer != setter) { - revert InvalidSignature(); - } - _onlyAuthorizedCaller(signer, collection, key, tokenId); - - _boolValues[collection][tokenId][_getIdForKey(key)] = value; - emit BoolAttributeUpdated(collection, tokenId, key, value); + _checkDeadlineAndSigner(setter, deadline, digest, v, r, s); + _setBoolAttribute(setter, collection, tokenId, key, value); } /** @@ -1076,10 +1230,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { bytes32 r, bytes32 s ) external { - if (block.timestamp > deadline) { - revert ExpiredDeadline(); - } - bytes32 digest = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", @@ -1096,14 +1246,8 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { ) ) ); - address signer = ecrecover(digest, v, r, s); - if (signer != setter) { - revert InvalidSignature(); - } - _onlyAuthorizedCaller(signer, collection, key, tokenId); - - _bytesValues[collection][tokenId][_getIdForKey(key)] = value; - emit BytesAttributeUpdated(collection, tokenId, key, value); + _checkDeadlineAndSigner(setter, deadline, digest, v, r, s); + _setBytesAttribute(setter, collection, tokenId, key, value); } /** @@ -1120,10 +1264,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { bytes32 r, bytes32 s ) external { - if (block.timestamp > deadline) { - revert ExpiredDeadline(); - } - bytes32 digest = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", @@ -1140,14 +1280,25 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { ) ) ); + _checkDeadlineAndSigner(setter, deadline, digest, v, r, s); + _setAddressAttribute(setter, collection, tokenId, key, value); + } + + function _checkDeadlineAndSigner( + address setter, + uint256 deadline, + bytes32 digest, + uint8 v, + bytes32 r, + bytes32 s + ) internal view { + if (block.timestamp > deadline) { + revert ExpiredDeadline(); + } address signer = ecrecover(digest, v, r, s); if (signer != setter) { revert InvalidSignature(); } - _onlyAuthorizedCaller(signer, collection, key, tokenId); - - _addressValues[collection][tokenId][_getIdForKey(key)] = value; - emit AddressAttributeUpdated(collection, tokenId, key, value); } /** @@ -1159,39 +1310,14 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { */ function _getIdForKey(string memory key) internal returns (uint256 keyID) { if (_keysToIds[key] == 0) { - _totalAttributes++; - _keysToIds[key] = _totalAttributes; - keyID = _totalAttributes; + _nextKeyId++; + _keysToIds[key] = _nextKeyId; + keyID = _nextKeyId; } else { keyID = _keysToIds[key]; } } - /** - * @notice Used to get the ID for a string value. If the value does not exist, a new ID is created. - * @dev IDs are shared among all tokens and used only for strings. - * @param collection Address of the collection being checked for string ID - * @param value The attribute value - * @return stringId The id for the string value - */ - function _getStringIdForValue( - address collection, - string memory value - ) internal returns (uint256 stringId) { - if (_stringValueToId[collection][value] == 0) { - _totalStringValues[collection]++; - _stringValueToId[collection][value] = _totalStringValues[ - collection - ]; - _stringIdToValue[collection][ - _totalStringValues[collection] - ] = value; - stringId = _totalStringValues[collection]; - } else { - stringId = _stringValueToId[collection][value]; - } - } - /** * @inheritdoc IERC165 */ diff --git a/docs/RMRK/extension/tokenAttributes/IERC7508.md b/docs/RMRK/extension/tokenAttributes/IERC7508.md index 32f8100e..28ee97a7 100644 --- a/docs/RMRK/extension/tokenAttributes/IERC7508.md +++ b/docs/RMRK/extension/tokenAttributes/IERC7508.md @@ -37,7 +37,7 @@ Used to retrieve the address type token attributes. ### getAddressAttributes ```solidity -function getAddressAttributes(address collection, uint256 tokenId, string[] addressKeys) external view returns (struct IERC7508.AddressAttribute[] attributes) +function getAddressAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (address[] attributes) ``` Used to get multiple address parameter values for a token. @@ -48,20 +48,20 @@ Used to get multiple address parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| addressKeys | string[] | An array of address keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of address keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.AddressAttribute[] | An array of `AddressAttribute` structs | +| attributes | address[] | An array of addresses, in the same order as the attribute keys | ### getAttributes ```solidity -function getAttributes(address collection, uint256 tokenId, string[] stringKeys, string[] uintKeys, string[] boolKeys, string[] addressKeys, string[] bytesKeys) external view returns (struct IERC7508.StringAttribute[] stringAttributes, struct IERC7508.UintAttribute[] uintAttributes, struct IERC7508.BoolAttribute[] boolAttributes, struct IERC7508.AddressAttribute[] addressAttributes, struct IERC7508.BytesAttribute[] bytesAttributes) +function getAttributes(address collection, uint256 tokenId, string[] stringKeys, string[] uintKeys, string[] boolKeys, string[] addressKeys, string[] bytesKeys) external view returns (string[] stringAttributes, uint256[] uintAttributes, bool[] boolAttributes, address[] addressAttributes, bytes[] bytesAttributes) ``` Used to retrieve multiple token attributes of any type at once. @@ -84,11 +84,33 @@ Used to retrieve multiple token attributes of any type at once. | Name | Type | Description | |---|---|---| -| stringAttributes | IERC7508.StringAttribute[] | An array of `StringAttribute` structs containing the string type attributes | -| uintAttributes | IERC7508.UintAttribute[] | An array of `UintAttribute` structs containing the uint type attributes | -| boolAttributes | IERC7508.BoolAttribute[] | An array of `BoolAttribute` structs containing the bool type attributes | -| addressAttributes | IERC7508.AddressAttribute[] | An array of `AddressAttribute` structs containing the address type attributes | -| bytesAttributes | IERC7508.BytesAttribute[] | An array of `BytesAttribute` structs containing the bytes type attributes | +| stringAttributes | string[] | An array of strings, in the same order as the stringKeys | +| uintAttributes | uint256[] | An array of uints, in the same order as the uintKeys | +| boolAttributes | bool[] | An array of bools, in the same order as the boolKeys | +| addressAttributes | address[] | An array of addresses, in the same order as the addressKeys | +| bytesAttributes | bytes[] | An array of bytes, in the same order as the bytesKeys | + +### getAttributesMetadataURI + +```solidity +function getAttributesMetadataURI(address collection) external view returns (string attributesMetadataURI) +``` + +Used to retrieve the attributes metadata URI for a collection, which contains all the information about the collection attributes. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| collection | address | Address of the collection | + +#### Returns + +| Name | Type | Description | +|---|---|---| +| attributesMetadataURI | string | The URI of the attributes metadata | ### getBoolAttribute @@ -117,7 +139,7 @@ Used to retrieve the bool type token attributes. ### getBoolAttributes ```solidity -function getBoolAttributes(address collection, uint256 tokenId, string[] boolKeys) external view returns (struct IERC7508.BoolAttribute[] attributes) +function getBoolAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (bool[] attributes) ``` Used to get multiple bool parameter values for a token. @@ -128,15 +150,15 @@ Used to get multiple bool parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| boolKeys | string[] | An array of bool keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of bool keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.BoolAttribute[] | An array of `BoolAttribute` structs | +| attributes | bool[] | An array of bools, in the same order as the attribute keys | ### getBytesAttribute @@ -165,7 +187,7 @@ Used to retrieve the bytes type token attributes. ### getBytesAttributes ```solidity -function getBytesAttributes(address collection, uint256 tokenId, string[] bytesKeys) external view returns (struct IERC7508.BytesAttribute[] attributes) +function getBytesAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (bytes[] attributes) ``` Used to get multiple bytes parameter values for a token. @@ -176,15 +198,15 @@ Used to get multiple bytes parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| bytesKeys | string[] | An array of bytes keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of bytes keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.BytesAttribute[] | An array of `BytesAttribute` structs | +| attributes | bytes[] | An array of bytes, in the same order as the attribute keys | ### getStringAttribute @@ -213,7 +235,7 @@ Used to retrieve the string type token attributes. ### getStringAttributes ```solidity -function getStringAttributes(address collection, uint256 tokenId, string[] stringKeys) external view returns (struct IERC7508.StringAttribute[] attributes) +function getStringAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (string[] attributes) ``` Used to get multiple sting parameter values for a token. @@ -224,15 +246,15 @@ Used to get multiple sting parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| stringKeys | string[] | An array of string keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of string keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.StringAttribute[] | An array of `StringAttribute` structs | +| attributes | string[] | An array of strings, in the same order as the attribute keys | ### getUintAttribute @@ -261,7 +283,7 @@ Used to retrieve the uint type token attributes. ### getUintAttributes ```solidity -function getUintAttributes(address collection, uint256 tokenId, string[] uintKeys) external view returns (struct IERC7508.UintAttribute[] attributes) +function getUintAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (uint256[] attributes) ``` Used to get multiple uint parameter values for a token. @@ -272,15 +294,15 @@ Used to get multiple uint parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| uintKeys | string[] | An array of uint keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of uint keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.UintAttribute[] | An array of `UintAttribute` structs | +| attributes | uint256[] | An array of uints, in the same order as the attribute keys | ### isCollaborator @@ -656,7 +678,7 @@ Used to set an address attribute. ### setAddressAttributes ```solidity -function setAddressAttributes(address collection, uint256 tokenId, IERC7508.AddressAttribute[] attributes) external nonpayable +function setAddressAttributes(address[] collections, uint256[] tokenIds, IERC7508.AddressAttribute[] attributes) external nonpayable ``` @@ -667,8 +689,8 @@ function setAddressAttributes(address collection, uint256 tokenId, IERC7508.Addr | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.AddressAttribute[] | undefined | ### setAttributes @@ -693,6 +715,23 @@ function setAttributes(address collection, uint256 tokenId, IERC7508.StringAttri | addressAttributes | IERC7508.AddressAttribute[] | undefined | | bytesAttributes | IERC7508.BytesAttribute[] | undefined | +### setAttributesMetadataURI + +```solidity +function setAttributesMetadataURI(address collection, string attributesMetadataURI) external nonpayable +``` + +Used to set the metadata URI for a collection, which contains all the information about the collection attributes. + +*Emits a {MetadataURIUpdated} event.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| collection | address | Address of the collection | +| attributesMetadataURI | string | The URI of the attributes metadata | + ### setBoolAttribute ```solidity @@ -715,7 +754,7 @@ Used to set a boolean attribute. ### setBoolAttributes ```solidity -function setBoolAttributes(address collection, uint256 tokenId, IERC7508.BoolAttribute[] attributes) external nonpayable +function setBoolAttributes(address[] collections, uint256[] tokenIds, IERC7508.BoolAttribute[] attributes) external nonpayable ``` @@ -726,8 +765,8 @@ function setBoolAttributes(address collection, uint256 tokenId, IERC7508.BoolAtt | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.BoolAttribute[] | undefined | ### setBytesAttribute @@ -752,7 +791,7 @@ Used to set an bytes attribute. ### setBytesAttributes ```solidity -function setBytesAttributes(address collection, uint256 tokenId, IERC7508.BytesAttribute[] attributes) external nonpayable +function setBytesAttributes(address[] collections, uint256[] tokenIds, IERC7508.BytesAttribute[] attributes) external nonpayable ``` @@ -763,8 +802,8 @@ function setBytesAttributes(address collection, uint256 tokenId, IERC7508.BytesA | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.BytesAttribute[] | undefined | ### setStringAttribute @@ -789,7 +828,7 @@ Used to set a string attribute. ### setStringAttributes ```solidity -function setStringAttributes(address collection, uint256 tokenId, IERC7508.StringAttribute[] attributes) external nonpayable +function setStringAttributes(address[] collections, uint256[] tokenIds, IERC7508.StringAttribute[] attributes) external nonpayable ``` @@ -800,8 +839,8 @@ function setStringAttributes(address collection, uint256 tokenId, IERC7508.Strin | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.StringAttribute[] | undefined | ### setUintAttribute @@ -826,7 +865,7 @@ Used to set a number attribute. ### setUintAttributes ```solidity -function setUintAttributes(address collection, uint256 tokenId, IERC7508.UintAttribute[] attributes) external nonpayable +function setUintAttributes(address[] collections, uint256[] tokenIds, IERC7508.UintAttribute[] attributes) external nonpayable ``` @@ -837,8 +876,8 @@ function setUintAttributes(address collection, uint256 tokenId, IERC7508.UintAtt | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.UintAttribute[] | undefined | ### supportsInterface @@ -980,6 +1019,23 @@ Used to notify listeners that a new collaborator has been added or removed. | collaborator `indexed` | address | Address of the collaborator | | isCollaborator | bool | A boolean value indicating whether the collaborator has been added (`true`) or removed (`false`) | +### MetadataURIUpdated + +```solidity +event MetadataURIUpdated(address indexed collection, string attributesMetadataURI) +``` + +Used to notify listeners that the metadata URI for a collection has been updated. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| collection `indexed` | address | Address of the collection | +| attributesMetadataURI | string | The new attributes metadata URI | + ### StringAttributeUpdated ```solidity diff --git a/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md b/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md index 2b05a4d1..352f69a3 100644 --- a/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md +++ b/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md @@ -139,7 +139,7 @@ Used to retrieve the address type token attributes. ### getAddressAttributes ```solidity -function getAddressAttributes(address collection, uint256 tokenId, string[] addressKeys) external view returns (struct IERC7508.AddressAttribute[] attributes) +function getAddressAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (address[] attributes) ``` Used to get multiple address parameter values for a token. @@ -150,20 +150,20 @@ Used to get multiple address parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| addressKeys | string[] | An array of address keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of address keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.AddressAttribute[] | An array of `AddressAttribute` structs | +| attributes | address[] | An array of addresses, in the same order as the attribute keys | ### getAttributes ```solidity -function getAttributes(address collection, uint256 tokenId, string[] stringKeys, string[] uintKeys, string[] boolKeys, string[] addressKeys, string[] bytesKeys) external view returns (struct IERC7508.StringAttribute[] stringAttributes, struct IERC7508.UintAttribute[] uintAttributes, struct IERC7508.BoolAttribute[] boolAttributes, struct IERC7508.AddressAttribute[] addressAttributes, struct IERC7508.BytesAttribute[] bytesAttributes) +function getAttributes(address collection, uint256 tokenId, string[] stringKeys, string[] uintKeys, string[] boolKeys, string[] addressKeys, string[] bytesKeys) external view returns (string[] stringAttributes, uint256[] uintAttributes, bool[] boolAttributes, address[] addressAttributes, bytes[] bytesAttributes) ``` Used to retrieve multiple token attributes of any type at once. @@ -186,11 +186,33 @@ Used to retrieve multiple token attributes of any type at once. | Name | Type | Description | |---|---|---| -| stringAttributes | IERC7508.StringAttribute[] | An array of `StringAttribute` structs containing the string type attributes | -| uintAttributes | IERC7508.UintAttribute[] | An array of `UintAttribute` structs containing the uint type attributes | -| boolAttributes | IERC7508.BoolAttribute[] | An array of `BoolAttribute` structs containing the bool type attributes | -| addressAttributes | IERC7508.AddressAttribute[] | An array of `AddressAttribute` structs containing the address type attributes | -| bytesAttributes | IERC7508.BytesAttribute[] | An array of `BytesAttribute` structs containing the bytes type attributes | +| stringAttributes | string[] | An array of strings, in the same order as the stringKeys | +| uintAttributes | uint256[] | An array of uints, in the same order as the uintKeys | +| boolAttributes | bool[] | An array of bools, in the same order as the boolKeys | +| addressAttributes | address[] | An array of addresses, in the same order as the addressKeys | +| bytesAttributes | bytes[] | An array of bytes, in the same order as the bytesKeys | + +### getAttributesMetadataURI + +```solidity +function getAttributesMetadataURI(address collection) external view returns (string attributesMetadataURI) +``` + +Used to retrieve the attributes metadata URI for a collection, which contains all the information about the collection attributes. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| collection | address | Address of the collection | + +#### Returns + +| Name | Type | Description | +|---|---|---| +| attributesMetadataURI | string | The URI of the attributes metadata | ### getBoolAttribute @@ -219,7 +241,7 @@ Used to retrieve the bool type token attributes. ### getBoolAttributes ```solidity -function getBoolAttributes(address collection, uint256 tokenId, string[] boolKeys) external view returns (struct IERC7508.BoolAttribute[] attributes) +function getBoolAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (bool[] attributes) ``` Used to get multiple bool parameter values for a token. @@ -230,15 +252,15 @@ Used to get multiple bool parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| boolKeys | string[] | An array of bool keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of bool keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.BoolAttribute[] | An array of `BoolAttribute` structs | +| attributes | bool[] | An array of bools, in the same order as the attribute keys | ### getBytesAttribute @@ -267,7 +289,7 @@ Used to retrieve the bytes type token attributes. ### getBytesAttributes ```solidity -function getBytesAttributes(address collection, uint256 tokenId, string[] bytesKeys) external view returns (struct IERC7508.BytesAttribute[] attributes) +function getBytesAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (bytes[] attributes) ``` Used to get multiple bytes parameter values for a token. @@ -278,15 +300,15 @@ Used to get multiple bytes parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| bytesKeys | string[] | An array of bytes keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of bytes keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.BytesAttribute[] | An array of `BytesAttribute` structs | +| attributes | bytes[] | An array of bytes, in the same order as the attribute keys | ### getStringAttribute @@ -315,7 +337,7 @@ Used to retrieve the string type token attributes. ### getStringAttributes ```solidity -function getStringAttributes(address collection, uint256 tokenId, string[] stringKeys) external view returns (struct IERC7508.StringAttribute[] attributes) +function getStringAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (string[] attributes) ``` Used to get multiple sting parameter values for a token. @@ -326,15 +348,15 @@ Used to get multiple sting parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| stringKeys | string[] | An array of string keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of string keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.StringAttribute[] | An array of `StringAttribute` structs | +| attributes | string[] | An array of strings, in the same order as the attribute keys | ### getUintAttribute @@ -363,7 +385,7 @@ Used to retrieve the uint type token attributes. ### getUintAttributes ```solidity -function getUintAttributes(address collection, uint256 tokenId, string[] uintKeys) external view returns (struct IERC7508.UintAttribute[] attributes) +function getUintAttributes(address[] collections, uint256[] tokenIds, string[] attributeKeys) external view returns (uint256[] attributes) ``` Used to get multiple uint parameter values for a token. @@ -374,15 +396,15 @@ Used to get multiple uint parameter values for a token. | Name | Type | Description | |---|---|---| -| collection | address | Address of the collection the token belongs to | -| tokenId | uint256 | ID of the token for which the attributes are being retrieved | -| uintKeys | string[] | An array of uint keys to retrieve | +| collections | address[] | Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. | +| tokenIds | uint256[] | IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. | +| attributeKeys | string[] | An array of uint keys to retrieve | #### Returns | Name | Type | Description | |---|---|---| -| attributes | IERC7508.UintAttribute[] | An array of `UintAttribute` structs | +| attributes | uint256[] | An array of uints, in the same order as the attribute keys | ### isCollaborator @@ -758,7 +780,7 @@ Used to set an address attribute. ### setAddressAttributes ```solidity -function setAddressAttributes(address collection, uint256 tokenId, IERC7508.AddressAttribute[] attributes) external nonpayable +function setAddressAttributes(address[] collections, uint256[] tokenIds, IERC7508.AddressAttribute[] attributes) external nonpayable ``` @@ -769,8 +791,8 @@ function setAddressAttributes(address collection, uint256 tokenId, IERC7508.Addr | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.AddressAttribute[] | undefined | ### setAttributes @@ -795,6 +817,23 @@ function setAttributes(address collection, uint256 tokenId, IERC7508.StringAttri | addressAttributes | IERC7508.AddressAttribute[] | undefined | | bytesAttributes | IERC7508.BytesAttribute[] | undefined | +### setAttributesMetadataURI + +```solidity +function setAttributesMetadataURI(address collection, string attributesMetadataURI) external nonpayable +``` + +Used to set the metadata URI for a collection, which contains all the information about the collection attributes. + +*Emits a {MetadataURIUpdated} event.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| collection | address | Address of the collection | +| attributesMetadataURI | string | The URI of the attributes metadata | + ### setBoolAttribute ```solidity @@ -817,7 +856,7 @@ Used to set a boolean attribute. ### setBoolAttributes ```solidity -function setBoolAttributes(address collection, uint256 tokenId, IERC7508.BoolAttribute[] attributes) external nonpayable +function setBoolAttributes(address[] collections, uint256[] tokenIds, IERC7508.BoolAttribute[] attributes) external nonpayable ``` @@ -828,8 +867,8 @@ function setBoolAttributes(address collection, uint256 tokenId, IERC7508.BoolAtt | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.BoolAttribute[] | undefined | ### setBytesAttribute @@ -854,7 +893,7 @@ Used to set an bytes attribute. ### setBytesAttributes ```solidity -function setBytesAttributes(address collection, uint256 tokenId, IERC7508.BytesAttribute[] attributes) external nonpayable +function setBytesAttributes(address[] collections, uint256[] tokenIds, IERC7508.BytesAttribute[] attributes) external nonpayable ``` @@ -865,8 +904,8 @@ function setBytesAttributes(address collection, uint256 tokenId, IERC7508.BytesA | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.BytesAttribute[] | undefined | ### setStringAttribute @@ -891,7 +930,7 @@ Used to set a string attribute. ### setStringAttributes ```solidity -function setStringAttributes(address collection, uint256 tokenId, IERC7508.StringAttribute[] attributes) external nonpayable +function setStringAttributes(address[] collections, uint256[] tokenIds, IERC7508.StringAttribute[] attributes) external nonpayable ``` @@ -902,8 +941,8 @@ function setStringAttributes(address collection, uint256 tokenId, IERC7508.Strin | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.StringAttribute[] | undefined | ### setUintAttribute @@ -928,7 +967,7 @@ Used to set a number attribute. ### setUintAttributes ```solidity -function setUintAttributes(address collection, uint256 tokenId, IERC7508.UintAttribute[] attributes) external nonpayable +function setUintAttributes(address[] collections, uint256[] tokenIds, IERC7508.UintAttribute[] attributes) external nonpayable ``` @@ -939,8 +978,8 @@ function setUintAttributes(address collection, uint256 tokenId, IERC7508.UintAtt | Name | Type | Description | |---|---|---| -| collection | address | undefined | -| tokenId | uint256 | undefined | +| collections | address[] | undefined | +| tokenIds | uint256[] | undefined | | attributes | IERC7508.UintAttribute[] | undefined | ### supportsInterface @@ -1082,6 +1121,23 @@ Used to notify listeners that a new collaborator has been added or removed. | collaborator `indexed` | address | Address of the collaborator | | isCollaborator | bool | A boolean value indicating whether the collaborator has been added (`true`) or removed (`false`) | +### MetadataURIUpdated + +```solidity +event MetadataURIUpdated(address indexed collection, string attributesMetadataURI) +``` + +Used to notify listeners that the metadata URI for a collection has been updated. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| collection `indexed` | address | Address of the collection | +| attributesMetadataURI | string | The new attributes metadata URI | + ### StringAttributeUpdated ```solidity @@ -1135,17 +1191,6 @@ Used to signal that the collaborator and collaborator rights array are not of eq -### CollectionAlreadyRegistered - -```solidity -error CollectionAlreadyRegistered() -``` - -Used to signal that the collection is already registered in the repository. - - - - ### CollectionNotRegistered ```solidity @@ -1179,6 +1224,17 @@ Used to signal that the presigned message's signature is invalid. +### LengthsMismatch + +```solidity +error LengthsMismatch() +``` + +Used to signal that the length of the arrays is not equal. + + + + ### NotCollectionCollaborator ```solidity diff --git a/test/extensions/tokenAttributesRepository.ts b/test/extensions/tokenAttributesRepository.ts index 7af82d34..53c7c4d9 100644 --- a/test/extensions/tokenAttributesRepository.ts +++ b/test/extensions/tokenAttributesRepository.ts @@ -40,12 +40,14 @@ describe('RMRKTokenAttributesRepository', async function () { let collectionOwner: SignerWithAddress; let tokenOwner: SignerWithAddress; let collaborator: SignerWithAddress; + let collectionAddress: string; const tokenId = 1n; const tokenId2 = 2n; beforeEach(async function () { tokenAttributes = await loadFixture(tokenAttributesFixture); ownedCollection = await loadFixture(ownedCollectionFixture); + collectionAddress = await ownedCollection.getAddress(); [collectionOwner, tokenOwner, collaborator] = await ethers.getSigners(); this.tokenAttributes = tokenAttributes; @@ -57,7 +59,7 @@ describe('RMRKTokenAttributesRepository', async function () { describe('Registering attributes and setting values', async function () { beforeEach(async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); @@ -66,156 +68,90 @@ describe('RMRKTokenAttributesRepository', async function () { it('can set and get token attributes', async function () { expect( await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'description', 'test description', ), ) .to.emit(tokenAttributes, 'StringAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'description', 'test description'); + .withArgs(collectionAddress, tokenId, 'description', 'test description'); expect( await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'description1', 'test description', ), ) .to.emit(tokenAttributes, 'StringAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'description1', 'test description'); - expect( - await tokenAttributes.setBoolAttribute( - await ownedCollection.getAddress(), - tokenId, - 'rare', - true, - ), - ) + .withArgs(collectionAddress, tokenId, 'description1', 'test description'); + expect(await tokenAttributes.setBoolAttribute(collectionAddress, tokenId, 'rare', true)) .to.emit(tokenAttributes, 'BoolAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'rare', true); + .withArgs(collectionAddress, tokenId, 'rare', true); expect( await tokenAttributes.setAddressAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'owner', tokenOwner.address, ), ) .to.emit(tokenAttributes, 'AddressAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'owner', tokenOwner.address); - expect( - await tokenAttributes.setUintAttribute( - await ownedCollection.getAddress(), - tokenId, - 'atk', - 100n, - ), - ) + .withArgs(collectionAddress, tokenId, 'owner', tokenOwner.address); + expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'atk', 100n)) .to.emit(tokenAttributes, 'UintAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'atk', 100n); - expect( - await tokenAttributes.setUintAttribute( - await ownedCollection.getAddress(), - tokenId, - 'health', - 100n, - ), - ) + .withArgs(collectionAddress, tokenId, 'atk', 100n); + expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 100n)) .to.emit(tokenAttributes, 'UintAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'health', 100n); - expect( - await tokenAttributes.setUintAttribute( - await ownedCollection.getAddress(), - tokenId, - 'health', - 95n, - ), - ) + .withArgs(collectionAddress, tokenId, 'health', 100n); + expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 95n)) .to.emit(tokenAttributes, 'UintAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'health', 95n); - expect( - await tokenAttributes.setUintAttribute( - await ownedCollection.getAddress(), - tokenId, - 'health', - 80n, - ), - ) + .withArgs(collectionAddress, tokenId, 'health', 95n); + expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 80n)) .to.emit(tokenAttributes, 'UintAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'health', 80n); - expect( - await tokenAttributes.setBytesAttribute( - await ownedCollection.getAddress(), - tokenId, - 'data', - '0x1234', - ), - ) + .withArgs(collectionAddress, tokenId, 'health', 80n); + expect(await tokenAttributes.setBytesAttribute(collectionAddress, tokenId, 'data', '0x1234')) .to.emit(tokenAttributes, 'BytesAttributeSet') - .withArgs(await ownedCollection.getAddress(), tokenId, 'data', '0x1234'); + .withArgs(collectionAddress, tokenId, 'data', '0x1234'); expect( - await tokenAttributes.getStringAttribute( - await ownedCollection.getAddress(), - tokenId, - 'description', - ), + await tokenAttributes.getStringAttribute(collectionAddress, tokenId, 'description'), ).to.eql('test description'); expect( - await tokenAttributes.getStringAttribute( - await ownedCollection.getAddress(), - tokenId, - 'description1', - ), + await tokenAttributes.getStringAttribute(collectionAddress, tokenId, 'description1'), ).to.eql('test description'); - expect( - await tokenAttributes.getBoolAttribute(await ownedCollection.getAddress(), tokenId, 'rare'), - ).to.eql(true); - expect( - await tokenAttributes.getAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'owner', - ), - ).to.eql(tokenOwner.address); - expect( - await tokenAttributes.getUintAttribute(await ownedCollection.getAddress(), tokenId, 'atk'), - ).to.eql(100n); - expect( - await tokenAttributes.getUintAttribute( - await ownedCollection.getAddress(), - tokenId, - 'health', - ), - ).to.eql(80n); - expect( - await tokenAttributes.getBytesAttribute( - await ownedCollection.getAddress(), - tokenId, - 'data', - ), - ).to.eql('0x1234'); + expect(await tokenAttributes.getBoolAttribute(collectionAddress, tokenId, 'rare')).to.eql( + true, + ); + expect(await tokenAttributes.getAddressAttribute(collectionAddress, tokenId, 'owner')).to.eql( + tokenOwner.address, + ); + expect(await tokenAttributes.getUintAttribute(collectionAddress, tokenId, 'atk')).to.eql( + 100n, + ); + expect(await tokenAttributes.getUintAttribute(collectionAddress, tokenId, 'health')).to.eql( + 80n, + ); + expect(await tokenAttributes.getBytesAttribute(collectionAddress, tokenId, 'data')).to.eql( + '0x1234', + ); await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'description', 'test description update', ); expect( - await tokenAttributes.getStringAttribute( - await ownedCollection.getAddress(), - tokenId, - 'description', - ), + await tokenAttributes.getStringAttribute(collectionAddress, tokenId, 'description'), ).to.eql('test description update'); }); it('can set multiple attributes of multiple types at the same time', async function () { await expect( tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [ { key: 'string1', value: 'value1' }, @@ -240,35 +176,30 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string1', 'value1') + .withArgs(collectionAddress, tokenId, 'string1', 'value1') .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string2', 'value2') + .withArgs(collectionAddress, tokenId, 'string2', 'value2') .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint1', 1n) + .withArgs(collectionAddress, tokenId, 'uint1', 1n) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint2', 2n) + .withArgs(collectionAddress, tokenId, 'uint2', 2n) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool1', true) + .withArgs(collectionAddress, tokenId, 'bool1', true) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool2', false) + .withArgs(collectionAddress, tokenId, 'bool2', false) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'address1', tokenOwner.address) + .withArgs(collectionAddress, tokenId, 'address1', tokenOwner.address) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs( - await ownedCollection.getAddress(), - tokenId, - 'address2', - await collectionOwner.getAddress(), - ) + .withArgs(collectionAddress, tokenId, 'address2', await collectionOwner.getAddress()) .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes1', '0x1234') + .withArgs(collectionAddress, tokenId, 'bytes1', '0x1234') .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes2', '0x5678'); + .withArgs(collectionAddress, tokenId, 'bytes2', '0x5678'); }); it('can update multiple attributes of multiple types at the same time', async function () { await tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [ { key: 'string1', value: 'value0' }, @@ -294,7 +225,7 @@ describe('RMRKTokenAttributesRepository', async function () { await expect( tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [ { key: 'string1', value: 'value1' }, @@ -319,35 +250,30 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string1', 'value1') + .withArgs(collectionAddress, tokenId, 'string1', 'value1') .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string2', 'value2') + .withArgs(collectionAddress, tokenId, 'string2', 'value2') .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint1', 1n) + .withArgs(collectionAddress, tokenId, 'uint1', 1n) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint2', 2n) + .withArgs(collectionAddress, tokenId, 'uint2', 2n) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool1', true) + .withArgs(collectionAddress, tokenId, 'bool1', true) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool2', false) + .withArgs(collectionAddress, tokenId, 'bool2', false) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'address1', tokenOwner.address) + .withArgs(collectionAddress, tokenId, 'address1', tokenOwner.address) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs( - await ownedCollection.getAddress(), - tokenId, - 'address2', - await collectionOwner.getAddress(), - ) + .withArgs(collectionAddress, tokenId, 'address2', await collectionOwner.getAddress()) .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes1', '0x1234') + .withArgs(collectionAddress, tokenId, 'bytes1', '0x1234') .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes2', '0x5678'); + .withArgs(collectionAddress, tokenId, 'bytes2', '0x5678'); }); it('can set and update multiple attributes of multiple types at the same time even if not all types are updated at the same time', async function () { await tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [{ key: 'string1', value: 'value0' }], [ @@ -367,7 +293,7 @@ describe('RMRKTokenAttributesRepository', async function () { await expect( tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [], [ @@ -389,30 +315,25 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint1', 1n) + .withArgs(collectionAddress, tokenId, 'uint1', 1n) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint2', 2n) + .withArgs(collectionAddress, tokenId, 'uint2', 2n) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool1', true) + .withArgs(collectionAddress, tokenId, 'bool1', true) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool2', false) + .withArgs(collectionAddress, tokenId, 'bool2', false) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'address1', tokenOwner.address) + .withArgs(collectionAddress, tokenId, 'address1', tokenOwner.address) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs( - await ownedCollection.getAddress(), - tokenId, - 'address2', - await collectionOwner.getAddress(), - ) + .withArgs(collectionAddress, tokenId, 'address2', await collectionOwner.getAddress()) .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes1', '0x1234') + .withArgs(collectionAddress, tokenId, 'bytes1', '0x1234') .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes2', '0x5678'); + .withArgs(collectionAddress, tokenId, 'bytes2', '0x5678'); await expect( tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [], [], @@ -425,15 +346,15 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool1', false) + .withArgs(collectionAddress, tokenId, 'bool1', false) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool2', true); + .withArgs(collectionAddress, tokenId, 'bool2', true); }); it('can set and update multiple attributes of multiple types at the same time', async function () { await expect( tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [ { key: 'string1', value: 'value1' }, @@ -458,35 +379,30 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string1', 'value1') + .withArgs(collectionAddress, tokenId, 'string1', 'value1') .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string2', 'value2') + .withArgs(collectionAddress, tokenId, 'string2', 'value2') .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint1', 1n) + .withArgs(collectionAddress, tokenId, 'uint1', 1n) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint2', 2n) + .withArgs(collectionAddress, tokenId, 'uint2', 2n) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool1', true) + .withArgs(collectionAddress, tokenId, 'bool1', true) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool2', false) + .withArgs(collectionAddress, tokenId, 'bool2', false) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'address1', tokenOwner.address) + .withArgs(collectionAddress, tokenId, 'address1', tokenOwner.address) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs( - await ownedCollection.getAddress(), - tokenId, - 'address2', - await collectionOwner.getAddress(), - ) + .withArgs(collectionAddress, tokenId, 'address2', await collectionOwner.getAddress()) .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes1', '0x1234') + .withArgs(collectionAddress, tokenId, 'bytes1', '0x1234') .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes2', '0x5678'); + .withArgs(collectionAddress, tokenId, 'bytes2', '0x5678'); }); it('should allow to retrieve multiple attributes at once', async function () { await tokenAttributes.setAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [ { key: 'string1', value: 'value1' }, @@ -512,7 +428,7 @@ describe('RMRKTokenAttributesRepository', async function () { expect( await tokenAttributes.getAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, ['string1', 'string2'], ['uint1', 'uint2'], @@ -521,44 +437,33 @@ describe('RMRKTokenAttributesRepository', async function () { ['bytes1', 'bytes2'], ), ).to.eql([ - [ - ['string1', 'value1'], - ['string2', 'value2'], - ], - [ - ['uint1', 1n], - ['uint2', 2n], - ], - [ - ['bool1', true], - ['bool2', false], - ], - [ - ['address1', tokenOwner.address], - ['address2', await collectionOwner.getAddress()], - ], - [ - ['bytes1', '0x1234'], - ['bytes2', '0x5678'], - ], + ['value1', 'value2'], + [1n, 2n], + [true, false], + [tokenOwner.address, await collectionOwner.getAddress()], + ['0x1234', '0x5678'], ]); }); it('can set multiple string attributes at the same time', async function () { await expect( - tokenAttributes.setStringAttributes(await ownedCollection.getAddress(), tokenId, [ - { key: 'string1', value: 'value1' }, - { key: 'string2', value: 'value2' }, - ]), + tokenAttributes.setStringAttributes( + [collectionAddress], + [tokenId], + [ + { key: 'string1', value: 'value1' }, + { key: 'string2', value: 'value2' }, + ], + ), ) .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string1', 'value1') + .withArgs(collectionAddress, tokenId, 'string1', 'value1') .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'string2', 'value2'); + .withArgs(collectionAddress, tokenId, 'string2', 'value2'); expect( await tokenAttributes.getAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, ['string1', 'string2'], [], @@ -566,33 +471,28 @@ describe('RMRKTokenAttributesRepository', async function () { [], [], ), - ).to.eql([ - [ - ['string1', 'value1'], - ['string2', 'value2'], - ], - [], - [], - [], - [], - ]); + ).to.eql([['value1', 'value2'], [], [], [], []]); }); it('can set multiple uint attributes at the same time', async function () { await expect( - tokenAttributes.setUintAttributes(await ownedCollection.getAddress(), tokenId, [ - { key: 'uint1', value: 1n }, - { key: 'uint2', value: 2n }, - ]), + tokenAttributes.setUintAttributes( + [collectionAddress], + [tokenId], + [ + { key: 'uint1', value: 1n }, + { key: 'uint2', value: 2n }, + ], + ), ) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint1', 1n) + .withArgs(collectionAddress, tokenId, 'uint1', 1n) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'uint2', 2n); + .withArgs(collectionAddress, tokenId, 'uint2', 2n); expect( await tokenAttributes.getAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [], ['uint1', 'uint2'], @@ -600,33 +500,28 @@ describe('RMRKTokenAttributesRepository', async function () { [], [], ), - ).to.eql([ - [], - [ - ['uint1', 1n], - ['uint2', 2n], - ], - [], - [], - [], - ]); + ).to.eql([[], [1n, 2n], [], [], []]); }); it('can set multiple bool attributes at the same time', async function () { await expect( - tokenAttributes.setBoolAttributes(await ownedCollection.getAddress(), tokenId, [ - { key: 'bool1', value: true }, - { key: 'bool2', value: false }, - ]), + tokenAttributes.setBoolAttributes( + [collectionAddress], + [tokenId], + [ + { key: 'bool1', value: true }, + { key: 'bool2', value: false }, + ], + ), ) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool1', true) + .withArgs(collectionAddress, tokenId, 'bool1', true) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bool2', false); + .withArgs(collectionAddress, tokenId, 'bool2', false); expect( await tokenAttributes.getAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [], [], @@ -634,38 +529,28 @@ describe('RMRKTokenAttributesRepository', async function () { [], [], ), - ).to.eql([ - [], - [], - [ - ['bool1', true], - ['bool2', false], - ], - [], - [], - ]); + ).to.eql([[], [], [true, false], [], []]); }); it('can set multiple address attributes at the same time', async function () { await expect( - tokenAttributes.setAddressAttributes(await ownedCollection.getAddress(), tokenId, [ - { key: 'address1', value: tokenOwner.address }, - { key: 'address2', value: await collectionOwner.getAddress() }, - ]), + tokenAttributes.setAddressAttributes( + [collectionAddress], + [tokenId], + [ + { key: 'address1', value: tokenOwner.address }, + { key: 'address2', value: await collectionOwner.getAddress() }, + ], + ), ) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'address1', tokenOwner.address) + .withArgs(collectionAddress, tokenId, 'address1', tokenOwner.address) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs( - await ownedCollection.getAddress(), - tokenId, - 'address2', - await collectionOwner.getAddress(), - ); + .withArgs(collectionAddress, tokenId, 'address2', await collectionOwner.getAddress()); expect( await tokenAttributes.getAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [], [], @@ -673,33 +558,28 @@ describe('RMRKTokenAttributesRepository', async function () { ['address1', 'address2'], [], ), - ).to.eql([ - [], - [], - [], - [ - ['address1', tokenOwner.address], - ['address2', await collectionOwner.getAddress()], - ], - [], - ]); + ).to.eql([[], [], [], [tokenOwner.address, await collectionOwner.getAddress()], []]); }); it('can set multiple bytes attributes at the same time', async function () { await expect( - tokenAttributes.setBytesAttributes(await ownedCollection.getAddress(), tokenId, [ - { key: 'bytes1', value: '0x1234' }, - { key: 'bytes2', value: '0x5678' }, - ]), + tokenAttributes.setBytesAttributes( + [collectionAddress], + [tokenId], + [ + { key: 'bytes1', value: '0x1234' }, + { key: 'bytes2', value: '0x5678' }, + ], + ), ) .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes1', '0x1234') + .withArgs(collectionAddress, tokenId, 'bytes1', '0x1234') .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), tokenId, 'bytes2', '0x5678'); + .withArgs(collectionAddress, tokenId, 'bytes2', '0x5678'); expect( await tokenAttributes.getAttributes( - await ownedCollection.getAddress(), + collectionAddress, tokenId, [], [], @@ -707,132 +587,75 @@ describe('RMRKTokenAttributesRepository', async function () { [], ['bytes1', 'bytes2'], ), - ).to.eql([ - [], - [], - [], - [], - [ - ['bytes1', '0x1234'], - ['bytes2', '0x5678'], - ], - ]); + ).to.eql([[], [], [], [], ['0x1234', '0x5678']]); }); it('can reuse keys and values are fine', async function () { - await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', + await tokenAttributes.setStringAttribute(collectionAddress, tokenId, 'X', 'X1'); + await tokenAttributes.setStringAttribute(collectionAddress, tokenId2, 'X', 'X2'); + + expect(await tokenAttributes.getStringAttribute(collectionAddress, tokenId, 'X')).to.eql( 'X1', ); - await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), - tokenId2, - 'X', + expect(await tokenAttributes.getStringAttribute(collectionAddress, tokenId2, 'X')).to.eql( 'X2', ); - - expect( - await tokenAttributes.getStringAttribute(await ownedCollection.getAddress(), tokenId, 'X'), - ).to.eql('X1'); - expect( - await tokenAttributes.getStringAttribute(await ownedCollection.getAddress(), tokenId2, 'X'), - ).to.eql('X2'); }); it('can reuse keys among different attributes and values are fine', async function () { - await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - 'test description', - ); - await tokenAttributes.setBoolAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - true, - ); + await tokenAttributes.setStringAttribute(collectionAddress, tokenId, 'X', 'test description'); + await tokenAttributes.setBoolAttribute(collectionAddress, tokenId, 'X', true); await tokenAttributes.setAddressAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, ); - await tokenAttributes.setUintAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - 100n, + await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'X', 100n); + await tokenAttributes.setBytesAttribute(collectionAddress, tokenId, 'X', '0x1234'); + + expect(await tokenAttributes.getStringAttribute(collectionAddress, tokenId, 'X')).to.eql( + 'test description', ); - await tokenAttributes.setBytesAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', + expect(await tokenAttributes.getBoolAttribute(collectionAddress, tokenId, 'X')).to.eql(true); + expect(await tokenAttributes.getAddressAttribute(collectionAddress, tokenId, 'X')).to.eql( + tokenOwner.address, + ); + expect(await tokenAttributes.getUintAttribute(collectionAddress, tokenId, 'X')).to.eql(100n); + expect(await tokenAttributes.getBytesAttribute(collectionAddress, tokenId, 'X')).to.eql( '0x1234', ); - - expect( - await tokenAttributes.getStringAttribute(await ownedCollection.getAddress(), tokenId, 'X'), - ).to.eql('test description'); - expect( - await tokenAttributes.getBoolAttribute(await ownedCollection.getAddress(), tokenId, 'X'), - ).to.eql(true); - expect( - await tokenAttributes.getAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X'), - ).to.eql(tokenOwner.address); - expect( - await tokenAttributes.getUintAttribute(await ownedCollection.getAddress(), tokenId, 'X'), - ).to.eql(100n); - expect( - await tokenAttributes.getBytesAttribute(await ownedCollection.getAddress(), tokenId, 'X'), - ).to.eql('0x1234'); }); it('can reuse string values and values are fine', async function () { - await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', + await tokenAttributes.setStringAttribute(collectionAddress, tokenId, 'X', 'common string'); + await tokenAttributes.setStringAttribute(collectionAddress, tokenId2, 'X', 'common string'); + + expect(await tokenAttributes.getStringAttribute(collectionAddress, tokenId, 'X')).to.eql( 'common string', ); - await tokenAttributes.setStringAttribute( - await ownedCollection.getAddress(), - tokenId2, - 'X', + expect(await tokenAttributes.getStringAttribute(collectionAddress, tokenId2, 'X')).to.eql( 'common string', ); - - expect( - await tokenAttributes.getStringAttribute(await ownedCollection.getAddress(), tokenId, 'X'), - ).to.eql('common string'); - expect( - await tokenAttributes.getStringAttribute(await ownedCollection.getAddress(), tokenId2, 'X'), - ).to.eql('common string'); }); it('should not allow to set string values to unauthorized caller', async function () { await expect( tokenAttributes .connect(tokenOwner) - .setStringAttribute(await ownedCollection.getAddress(), tokenId, 'X', 'test description'), + .setStringAttribute(collectionAddress, tokenId, 'X', 'test description'), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); it('should not allow to set uint values to unauthorized caller', async function () { await expect( - tokenAttributes - .connect(tokenOwner) - .setUintAttribute(await ownedCollection.getAddress(), tokenId, 'X', 42n), + tokenAttributes.connect(tokenOwner).setUintAttribute(collectionAddress, tokenId, 'X', 42n), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); it('should not allow to set boolean values to unauthorized caller', async function () { await expect( - tokenAttributes - .connect(tokenOwner) - .setBoolAttribute(await ownedCollection.getAddress(), tokenId, 'X', true), + tokenAttributes.connect(tokenOwner).setBoolAttribute(collectionAddress, tokenId, 'X', true), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); @@ -840,12 +663,7 @@ describe('RMRKTokenAttributesRepository', async function () { await expect( tokenAttributes .connect(tokenOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); @@ -853,37 +671,33 @@ describe('RMRKTokenAttributesRepository', async function () { await expect( tokenAttributes .connect(tokenOwner) - .setBytesAttribute(await ownedCollection.getAddress(), tokenId, 'X', '0x1234'), + .setBytesAttribute(collectionAddress, tokenId, 'X', '0x1234'), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); }); describe('Token attributes access control', async function () { - it('should not allow registering an already registered collection', async function () { + it('should allow registering an already registered collection', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); await expect( tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ), - ).to.be.revertedWithCustomError(tokenAttributes, 'CollectionAlreadyRegistered'); + ).to.emit(tokenAttributes, 'AccessControlRegistration'); }); it('should not allow to register a collection if caller is not the owner of the collection', async function () { await expect( tokenAttributes .connect(tokenOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - true, - ), + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), true), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); @@ -901,7 +715,7 @@ describe('RMRKTokenAttributesRepository', async function () { it('should allow to manage access control for registered collections', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); @@ -910,19 +724,19 @@ describe('RMRKTokenAttributesRepository', async function () { await tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, ), ) .to.emit(tokenAttributes, 'AccessControlUpdate') - .withArgs(await ownedCollection.getAddress(), 'X', 2, tokenOwner); + .withArgs(collectionAddress, 'X', 2, tokenOwner); }); it('should allow issuer to manage collaborators', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); @@ -930,23 +744,23 @@ describe('RMRKTokenAttributesRepository', async function () { expect( await tokenAttributes .connect(collectionOwner) - .manageCollaborators(await ownedCollection.getAddress(), [tokenOwner.address], [true]), + .manageCollaborators(collectionAddress, [tokenOwner.address], [true]), ) .to.emit(tokenAttributes, 'CollaboratorUpdate') - .withArgs(await ownedCollection.getAddress(), [tokenOwner.address], [true]); + .withArgs(collectionAddress, [tokenOwner.address], [true]); }); it('should not allow to manage collaborators of an unregistered collection', async function () { await expect( tokenAttributes .connect(collectionOwner) - .manageCollaborators(await ownedCollection.getAddress(), [tokenOwner.address], [true]), + .manageCollaborators(collectionAddress, [tokenOwner.address], [true]), ).to.be.revertedWithCustomError(tokenAttributes, 'CollectionNotRegistered'); }); it('should not allow to manage collaborators if the caller is not the issuer', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); @@ -954,13 +768,13 @@ describe('RMRKTokenAttributesRepository', async function () { await expect( tokenAttributes .connect(tokenOwner) - .manageCollaborators(await ownedCollection.getAddress(), [tokenOwner.address], [true]), + .manageCollaborators(collectionAddress, [tokenOwner.address], [true]), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); it('should not allow to manage collaborators for registered collections if collaborator arrays are not of equal length', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); @@ -969,7 +783,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(collectionOwner) .manageCollaborators( - await ownedCollection.getAddress(), + collectionAddress, [tokenOwner.address, await collectionOwner.getAddress()], [true], ), @@ -981,7 +795,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, @@ -991,7 +805,7 @@ describe('RMRKTokenAttributesRepository', async function () { it('should not allow to manage access control if the caller is not issuer', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); @@ -1000,7 +814,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(tokenOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, @@ -1010,7 +824,7 @@ describe('RMRKTokenAttributesRepository', async function () { it('should not allow to manage access control if the caller is not returned as collection owner when using ownable', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), true, ); @@ -1019,7 +833,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(tokenOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, @@ -1029,155 +843,100 @@ describe('RMRKTokenAttributesRepository', async function () { it('should return the expected value when checking for collaborators', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); - expect( - await tokenAttributes.isCollaborator( - tokenOwner.address, - await ownedCollection.getAddress(), - ), - ).to.be.false; + expect(await tokenAttributes.isCollaborator(tokenOwner.address, collectionAddress)).to.be + .false; await tokenAttributes .connect(collectionOwner) - .manageCollaborators(await ownedCollection.getAddress(), [tokenOwner.address], [true]); + .manageCollaborators(collectionAddress, [tokenOwner.address], [true]); - expect( - await tokenAttributes.isCollaborator( - tokenOwner.address, - await ownedCollection.getAddress(), - ), - ).to.be.true; + expect(await tokenAttributes.isCollaborator(tokenOwner.address, collectionAddress)).to.be + .true; }); it('should return the expected value when checking for specific addresses', async function () { await tokenAttributes.registerAccessControl( - await ownedCollection.getAddress(), + collectionAddress, await collectionOwner.getAddress(), false, ); - expect( - await tokenAttributes.isSpecificAddress( - tokenOwner.address, - await ownedCollection.getAddress(), - 'X', - ), - ).to.be.false; + expect(await tokenAttributes.isSpecificAddress(tokenOwner.address, collectionAddress, 'X')).to + .be.false; await tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, ); - expect( - await tokenAttributes.isSpecificAddress( - tokenOwner.address, - await ownedCollection.getAddress(), - 'X', - ), - ).to.be.true; + expect(await tokenAttributes.isSpecificAddress(tokenOwner.address, collectionAddress, 'X')).to + .be.true; }); it('should use the issuer returned from the collection when using only issuer when only issuer is allowed to manage parameter', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - true, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), true); await tokenAttributes .connect(collectionOwner) - .manageAccessControl( - await ownedCollection.getAddress(), - 'X', - AccessType.Issuer, - ethers.ZeroAddress, - ); + .manageAccessControl(collectionAddress, 'X', AccessType.Issuer, ethers.ZeroAddress); await expect( tokenAttributes .connect(tokenOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); await expect( tokenAttributes .connect(tokenOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuer'); }); it('should only allow collaborator to modify the parameters if only collaborator is allowed to modify them', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - false, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), false); await tokenAttributes .connect(collectionOwner) - .manageAccessControl( - await ownedCollection.getAddress(), - 'X', - AccessType.Collaborator, - ethers.ZeroAddress, - ); + .manageAccessControl(collectionAddress, 'X', AccessType.Collaborator, ethers.ZeroAddress); await tokenAttributes .connect(collectionOwner) - .manageCollaborators(await ownedCollection.getAddress(), [tokenOwner.address], [true]); + .manageCollaborators(collectionAddress, [tokenOwner.address], [true]); await tokenAttributes .connect(tokenOwner) - .setAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X', tokenOwner.address); + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address); await expect( tokenAttributes .connect(collectionOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionCollaborator'); }); it('should only allow issuer and collaborator to modify the parameters if only issuer and collaborator is allowed to modify them', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - false, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), false); await tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, ethers.ZeroAddress, @@ -1185,41 +944,32 @@ describe('RMRKTokenAttributesRepository', async function () { await tokenAttributes .connect(collectionOwner) - .setAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X', tokenOwner.address); + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address); await expect( tokenAttributes .connect(tokenOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuerOrCollaborator'); await tokenAttributes .connect(collectionOwner) - .manageCollaborators(await ownedCollection.getAddress(), [tokenOwner.address], [true]); + .manageCollaborators(collectionAddress, [tokenOwner.address], [true]); await tokenAttributes .connect(tokenOwner) - .setAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X', tokenOwner.address); + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address); }); it('should only allow issuer and collaborator to modify the parameters if only issuer and collaborator is allowed to modify them even when using the ownable', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - true, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), true); await tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, ethers.ZeroAddress, @@ -1227,90 +977,58 @@ describe('RMRKTokenAttributesRepository', async function () { await tokenAttributes .connect(collectionOwner) - .setAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X', tokenOwner.address); + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address); await expect( tokenAttributes .connect(tokenOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotCollectionIssuerOrCollaborator'); await tokenAttributes .connect(collectionOwner) - .manageCollaborators( - await ownedCollection.getAddress(), - [await collaborator.getAddress()], - [true], - ); + .manageCollaborators(collectionAddress, [await collaborator.getAddress()], [true]); await tokenAttributes .connect(collaborator) - .setAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X', tokenOwner.address); + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address); }); it('should only allow token owner to modify the parameters if only token owner is allowed to modify them', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - false, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), false); await tokenAttributes .connect(collectionOwner) - .manageAccessControl( - await ownedCollection.getAddress(), - 'X', - AccessType.TokenOwner, - ethers.ZeroAddress, - ); + .manageAccessControl(collectionAddress, 'X', AccessType.TokenOwner, ethers.ZeroAddress); await expect( tokenAttributes .connect(collaborator) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotTokenOwner'); await expect( tokenAttributes .connect(collectionOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotTokenOwner'); await tokenAttributes .connect(tokenOwner) - .setAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X', tokenOwner.address); + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address); }); it('should only allow specific address to modify the parameters if only specific address is allowed to modify them', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - false, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), false); await tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.SpecificAddress, ethers.ZeroAddress, @@ -1319,18 +1037,13 @@ describe('RMRKTokenAttributesRepository', async function () { await expect( tokenAttributes .connect(tokenOwner) - .setAddressAttribute( - await ownedCollection.getAddress(), - tokenId, - 'X', - tokenOwner.address, - ), + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address), ).to.be.revertedWithCustomError(tokenAttributes, 'NotSpecificAddress'); await tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.SpecificAddress, tokenOwner.address, @@ -1338,48 +1051,44 @@ describe('RMRKTokenAttributesRepository', async function () { await tokenAttributes .connect(tokenOwner) - .setAddressAttribute(await ownedCollection.getAddress(), tokenId, 'X', tokenOwner.address); + .setAddressAttribute(collectionAddress, tokenId, 'X', tokenOwner.address); }); it('should allow to use presigned message to modify the parameters', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - false, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), false); const uintMessage = await tokenAttributes.prepareMessageToPresignUintAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, 9999999999n, ); const stringMessage = await tokenAttributes.prepareMessageToPresignStringAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', 9999999999n, ); const boolMessage = await tokenAttributes.prepareMessageToPresignBoolAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, 9999999999n, ); const bytesMessage = await tokenAttributes.prepareMessageToPresignBytesAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', 9999999999n, ); const addressMessage = await tokenAttributes.prepareMessageToPresignAddressAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1417,7 +1126,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1428,13 +1137,13 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), 1, 'X', 1); + .withArgs(collectionAddress, 1, 'X', 1); await expect( tokenAttributes .connect(tokenOwner) .presignedSetStringAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', @@ -1445,13 +1154,13 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), 1, 'X', 'test'); + .withArgs(collectionAddress, 1, 'X', 'test'); await expect( tokenAttributes .connect(tokenOwner) .presignedSetBoolAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, @@ -1462,13 +1171,13 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), 1, 'X', true); + .withArgs(collectionAddress, 1, 'X', true); await expect( tokenAttributes .connect(tokenOwner) .presignedSetBytesAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', @@ -1479,13 +1188,13 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), 1, 'X', '0x1234'); + .withArgs(collectionAddress, 1, 'X', '0x1234'); await expect( tokenAttributes .connect(tokenOwner) .presignedSetAddressAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1496,50 +1205,46 @@ describe('RMRKTokenAttributesRepository', async function () { ), ) .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(await ownedCollection.getAddress(), 1, 'X', tokenOwner.address); + .withArgs(collectionAddress, 1, 'X', tokenOwner.address); }); it('should not allow to use presigned message to modify the parameters if the deadline has elapsed', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - false, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), false); await mine(1000, { interval: 15 }); const uintMessage = await tokenAttributes.prepareMessageToPresignUintAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, 10n, ); const stringMessage = await tokenAttributes.prepareMessageToPresignStringAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', 10n, ); const boolMessage = await tokenAttributes.prepareMessageToPresignBoolAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, 10n, ); const bytesMessage = await tokenAttributes.prepareMessageToPresignBytesAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', 10n, ); const addressMessage = await tokenAttributes.prepareMessageToPresignAddressAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1577,7 +1282,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1592,7 +1297,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetStringAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', @@ -1607,7 +1312,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBoolAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, @@ -1622,7 +1327,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBytesAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', @@ -1637,7 +1342,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetAddressAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1652,42 +1357,38 @@ describe('RMRKTokenAttributesRepository', async function () { it('should not allow to use presigned message to modify the parameters if the setter does not match the actual signer', async function () { await tokenAttributes .connect(collectionOwner) - .registerAccessControl( - await ownedCollection.getAddress(), - await collectionOwner.getAddress(), - false, - ); + .registerAccessControl(collectionAddress, await collectionOwner.getAddress(), false); const uintMessage = await tokenAttributes.prepareMessageToPresignUintAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, 9999999999n, ); const stringMessage = await tokenAttributes.prepareMessageToPresignStringAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', 9999999999n, ); const boolMessage = await tokenAttributes.prepareMessageToPresignBoolAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, 9999999999n, ); const bytesMessage = await tokenAttributes.prepareMessageToPresignBytesAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', 9999999999n, ); const addressMessage = await tokenAttributes.prepareMessageToPresignAddressAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1725,7 +1426,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1740,7 +1441,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetStringAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', @@ -1755,7 +1456,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBoolAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, @@ -1770,7 +1471,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBytesAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', @@ -1785,7 +1486,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetAddressAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1799,35 +1500,35 @@ describe('RMRKTokenAttributesRepository', async function () { it('should not allow to use presigned message to modify the parameters if the signer is not authorized to modify them', async function () { const uintMessage = await tokenAttributes.prepareMessageToPresignUintAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, 9999999999n, ); const stringMessage = await tokenAttributes.prepareMessageToPresignStringAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', 9999999999n, ); const boolMessage = await tokenAttributes.prepareMessageToPresignBoolAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, 9999999999n, ); const bytesMessage = await tokenAttributes.prepareMessageToPresignBytesAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', 9999999999n, ); const addressMessage = await tokenAttributes.prepareMessageToPresignAddressAttribute( - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1865,7 +1566,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1880,7 +1581,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetStringAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', @@ -1895,7 +1596,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBoolAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, @@ -1910,7 +1611,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBytesAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', @@ -1925,7 +1626,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetAddressAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, diff --git a/test/interfaces.ts b/test/interfaces.ts index 1db845b6..aab29664 100644 --- a/test/interfaces.ts +++ b/test/interfaces.ts @@ -7,7 +7,7 @@ export const IERC6220 = '0x28bc9ae4'; // Equippable and Composable export const IERC6454 = '0x91a6262f'; // Soulbound export const IERC7401 = '0x42b0e56f'; // Nestable export const IERC7409 = '0x1b3327ab'; // Emotes Repository -export const IERC7508 = '0x29b20880'; // Attributes Repository +export const IERC7508 = '0x62ee8e7a'; // Attributes Repository export const IERC7590 = '0x6f87c75c'; // ERC20 Token Holder export const IOtherInterface = '0xffffffff'; export const IRMRKCatalog = '0xd912401f'; // ERC6220