From 4fea571f9869613331f013e70d346f564b6c882a Mon Sep 17 00:00:00 2001 From: steven2308 Date: Fri, 1 Mar 2024 15:14:51 -0500 Subject: [PATCH 1/3] Refactor on token attributes to reuse code and allow multiple collections and tokenIds on setters and getters. --- .../extension/tokenAttributes/IERC7508.sol | 100 +-- .../RMRKTokenAttributesRepository.sol | 604 +++++++------ test/extensions/tokenAttributesRepository.ts | 809 ++++++------------ 3 files changed, 661 insertions(+), 852 deletions(-) diff --git a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol index 70fc8a5d..c0aa8735 100644 --- a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol +++ b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol @@ -326,13 +326,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 +343,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 +360,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 +377,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 +394,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; @@ -780,15 +780,15 @@ 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 + * @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 `StringAttribute` structs */ function getStringAttributes( - address collection, - uint256 tokenId, - string[] memory stringKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) external view returns (StringAttribute[] memory attributes); /** @@ -798,15 +798,15 @@ 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 + * @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 `UintAttribute` structs */ function getUintAttributes( - address collection, - uint256 tokenId, - string[] memory uintKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) external view returns (UintAttribute[] memory attributes); /** @@ -816,15 +816,15 @@ 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 + * @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 `BoolAttribute` structs */ function getBoolAttributes( - address collection, - uint256 tokenId, - string[] memory boolKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) external view returns (BoolAttribute[] memory attributes); /** @@ -834,15 +834,15 @@ 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 + * @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 `AddressAttribute` structs */ function getAddressAttributes( - address collection, - uint256 tokenId, - string[] memory addressKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) external view returns (AddressAttribute[] memory attributes); /** @@ -852,14 +852,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 + * @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 `BytesAttribute` structs */ function getBytesAttributes( - address collection, - uint256 tokenId, - string[] memory bytesKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) external view returns (BytesAttribute[] memory attributes); } diff --git a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol index a31bef1f..bf647086 100644 --- a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol +++ b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol @@ -44,35 +44,29 @@ 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 => AccessType)) private _parameterAccessType; - mapping(address => mapping(uint256 => address)) + mapping(address collection => mapping(uint256 => address)) private _parameterSpecificAddress; - mapping(address => IssuerSetting) private _issuerSettings; - mapping(address => mapping(address => bool)) private _collaborators; + mapping(address collection => IssuerSetting) private _issuerSettings; + mapping(address collection => mapping(address collaborator => bool)) + 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(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 +74,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 +84,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 +104,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 +119,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, @@ -235,17 +230,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 +303,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 +314,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 +325,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 +336,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 +347,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]]; } @@ -392,41 +373,50 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { BytesAttribute[] 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 + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) public view returns (StringAttribute[] memory attributes) { - uint256 stringLen = stringKeys.length; + uint256 length = attributeKeys.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - attributes = new StringAttribute[](stringLen); + attributes = new StringAttribute[](length); - for (uint256 i; i < stringLen; ) { + for (uint256 i; i < length; ) { attributes[i] = StringAttribute({ - key: stringKeys[i], - value: _stringIdToValue[collection][ - _stringValueIds[collection][tokenId][ - _keysToIds[stringKeys[i]] - ] - ] + key: attributeKeys[i], + value: getStringAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attributeKeys[i] + ) }); unchecked { ++i; @@ -438,18 +428,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getUintAttributes( - address collection, - uint256 tokenId, - string[] memory uintKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) public view returns (UintAttribute[] memory attributes) { - uint256 uintLen = uintKeys.length; + uint256 length = attributeKeys.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - attributes = new UintAttribute[](uintLen); + attributes = new UintAttribute[](length); - for (uint256 i; i < uintLen; ) { + for (uint256 i; i < length; ) { attributes[i] = UintAttribute({ - key: uintKeys[i], - value: _uintValues[collection][tokenId][_keysToIds[uintKeys[i]]] + key: attributeKeys[i], + value: getUintAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attributeKeys[i] + ) }); unchecked { ++i; @@ -461,18 +459,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getBoolAttributes( - address collection, - uint256 tokenId, - string[] memory boolKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) public view returns (BoolAttribute[] memory attributes) { - uint256 boolLen = boolKeys.length; + uint256 length = attributeKeys.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - attributes = new BoolAttribute[](boolLen); + attributes = new BoolAttribute[](length); - for (uint256 i; i < boolLen; ) { + for (uint256 i; i < length; ) { attributes[i] = BoolAttribute({ - key: boolKeys[i], - value: _boolValues[collection][tokenId][_keysToIds[boolKeys[i]]] + key: attributeKeys[i], + value: getBoolAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attributeKeys[i] + ) }); unchecked { ++i; @@ -484,19 +490,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getAddressAttributes( - address collection, - uint256 tokenId, - string[] memory addressKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) public view returns (AddressAttribute[] memory attributes) { - uint256 addressLen = addressKeys.length; - attributes = new AddressAttribute[](addressLen); + uint256 length = attributeKeys.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - for (uint256 i; i < addressLen; ) { + attributes = new AddressAttribute[](length); + + for (uint256 i; i < length; ) { attributes[i] = AddressAttribute({ - key: addressKeys[i], - value: _addressValues[collection][tokenId][ - _keysToIds[addressKeys[i]] - ] + key: attributeKeys[i], + value: getAddressAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attributeKeys[i] + ) }); unchecked { ++i; @@ -508,19 +521,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { * @inheritdoc IERC7508 */ function getBytesAttributes( - address collection, - uint256 tokenId, - string[] memory bytesKeys + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys ) public view returns (BytesAttribute[] memory attributes) { - uint256 bytesLen = bytesKeys.length; - attributes = new BytesAttribute[](bytesLen); + uint256 length = attributeKeys.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); + + attributes = new BytesAttribute[](length); - for (uint256 i; i < bytesLen; ) { + for (uint256 i; i < length; ) { attributes[i] = BytesAttribute({ - key: bytesKeys[i], - value: _bytesValues[collection][tokenId][ - _keysToIds[bytesKeys[i]] - ] + key: attributeKeys[i], + value: getBytesAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attributeKeys[i] + ) }); unchecked { ++i; @@ -646,84 +666,83 @@ 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) { + function setBoolAttributes( + address[] memory collections, + uint256[] memory tokenIds, + BoolAttribute[] memory attributes + ) external { uint256 length = attributes.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); for (uint256 i = 0; i < length; ) { - _stringValueIds[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = _getStringIdForValue(collection, attributes[i].value); - emit StringAttributeUpdated( + address collection = multipleCollections + ? collections[i] + : collections[0]; + uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + _setBoolAttribute( + _msgSender(), collection, tokenId, attributes[i].key, @@ -738,17 +757,23 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setUintAttributes( - address collection, - uint256 tokenId, - UintAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { + function setBytesAttributes( + address[] memory collections, + uint256[] memory tokenIds, + BytesAttribute[] memory attributes + ) external { uint256 length = attributes.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); for (uint256 i = 0; i < length; ) { - _uintValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit UintAttributeUpdated( + address collection = multipleCollections + ? collections[i] + : collections[0]; + uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + _setBytesAttribute( + _msgSender(), collection, tokenId, attributes[i].key, @@ -763,17 +788,23 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setBoolAttributes( - address collection, - uint256 tokenId, - BoolAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { + function setStringAttributes( + address[] memory collections, + uint256[] memory tokenIds, + StringAttribute[] memory attributes + ) external { uint256 length = attributes.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); for (uint256 i = 0; i < length; ) { - _boolValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit BoolAttributeUpdated( + address collection = multipleCollections + ? collections[i] + : collections[0]; + uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + _setStringAttribute( + _msgSender(), collection, tokenId, attributes[i].key, @@ -788,17 +819,23 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setAddressAttributes( - address collection, - uint256 tokenId, - AddressAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { + function setUintAttributes( + address[] memory collections, + uint256[] memory tokenIds, + UintAttribute[] memory attributes + ) external { uint256 length = attributes.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); for (uint256 i = 0; i < length; ) { - _addressValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit AddressAttributeUpdated( + address collection = multipleCollections + ? collections[i] + : collections[0]; + uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + _setUintAttribute( + _msgSender(), collection, tokenId, attributes[i].key, @@ -813,17 +850,23 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { /** * @inheritdoc IERC7508 */ - function setBytesAttributes( - address collection, - uint256 tokenId, - BytesAttribute[] memory attributes - ) external onlyAuthorizedCaller(collection, "", tokenId) { + function setAddressAttributes( + address[] memory collections, + uint256[] memory tokenIds, + AddressAttribute[] memory attributes + ) external { uint256 length = attributes.length; + ( + bool multipleCollections, + bool multipleTokens + ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); for (uint256 i = 0; i < length; ) { - _bytesValues[collection][tokenId][ - _getIdForKey(attributes[i].key) - ] = attributes[i].value; - emit BytesAttributeUpdated( + address collection = multipleCollections + ? collections[i] + : collections[0]; + uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + _setAddressAttribute( + _msgSender(), collection, tokenId, attributes[i].key, @@ -846,13 +889,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( + _setStringAttribute( + _msgSender(), collection, tokenId, stringAttributes[i].key, @@ -865,10 +906,8 @@ 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( + _setUintAttribute( + _msgSender(), collection, tokenId, uintAttributes[i].key, @@ -881,10 +920,8 @@ 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( + _setBoolAttribute( + _msgSender(), collection, tokenId, boolAttributes[i].key, @@ -897,10 +934,8 @@ 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( + _setAddressAttribute( + _msgSender(), collection, tokenId, addressAttributes[i].key, @@ -913,10 +948,8 @@ 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( + _setBytesAttribute( + _msgSender(), collection, tokenId, bytesAttributes[i].key, @@ -928,6 +961,81 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } } + function _checkIfMultipleCollectionsAndTokens( + address[] memory collections, + uint256[] memory tokenIds, + uint256 attributesLength + ) internal pure returns (bool multipleCollections, bool multipleTokens) { + multipleCollections = collections.length != 1; + multipleTokens = tokenIds.length != 1; + if ( + (multipleCollections && collections.length != attributesLength) || + (multipleTokens && tokenIds.length != attributesLength) + ) { + revert LengthsMismatch(); + } + } + + 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 +1050,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 +1066,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 +1084,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 +1100,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 +1118,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 +1134,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 +1152,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 +1168,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 +1186,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 +1202,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); } /** @@ -1167,31 +1240,6 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } } - /** - * @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/test/extensions/tokenAttributesRepository.ts b/test/extensions/tokenAttributesRepository.ts index 7af82d34..76f89c74 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'], @@ -546,19 +462,23 @@ describe('RMRKTokenAttributesRepository', async function () { 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'], [], @@ -580,19 +500,23 @@ describe('RMRKTokenAttributesRepository', async function () { 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'], @@ -614,19 +538,23 @@ describe('RMRKTokenAttributesRepository', async function () { 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, [], [], @@ -648,24 +576,23 @@ describe('RMRKTokenAttributesRepository', async function () { 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, [], [], @@ -687,19 +614,23 @@ describe('RMRKTokenAttributesRepository', async function () { 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, [], [], @@ -720,119 +651,71 @@ describe('RMRKTokenAttributesRepository', async function () { }); 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 +723,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 +731,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 +775,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 +784,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 +804,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 +828,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 +843,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(collectionOwner) .manageCollaborators( - await ownedCollection.getAddress(), + collectionAddress, [tokenOwner.address, await collectionOwner.getAddress()], [true], ), @@ -981,7 +855,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(collectionOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, @@ -991,7 +865,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 +874,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(tokenOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, @@ -1010,7 +884,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 +893,7 @@ describe('RMRKTokenAttributesRepository', async function () { tokenAttributes .connect(tokenOwner) .manageAccessControl( - await ownedCollection.getAddress(), + collectionAddress, 'X', AccessType.IssuerOrCollaborator, tokenOwner.address, @@ -1029,155 +903,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 +1004,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 +1037,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 +1097,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 +1111,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 +1186,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1428,13 +1197,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 +1214,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 +1231,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 +1248,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 +1265,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 +1342,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1592,7 +1357,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetStringAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', @@ -1607,7 +1372,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBoolAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, @@ -1622,7 +1387,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBytesAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', @@ -1637,7 +1402,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetAddressAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1652,42 +1417,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 +1486,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1740,7 +1501,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetStringAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', @@ -1755,7 +1516,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBoolAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, @@ -1770,7 +1531,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBytesAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', @@ -1785,7 +1546,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetAddressAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, @@ -1799,35 +1560,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 +1626,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetUintAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 1, @@ -1880,7 +1641,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetStringAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', 'test', @@ -1895,7 +1656,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBoolAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', true, @@ -1910,7 +1671,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetBytesAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', '0x1234', @@ -1925,7 +1686,7 @@ describe('RMRKTokenAttributesRepository', async function () { .connect(tokenOwner) .presignedSetAddressAttribute( await collectionOwner.getAddress(), - await ownedCollection.getAddress(), + collectionAddress, tokenId, 'X', tokenOwner.address, From bdd9ec52bbfe2dc1ad45e0f93c1d5ca6fabbfdab Mon Sep 17 00:00:00 2001 From: steven2308 Date: Mon, 4 Mar 2024 21:00:31 -0500 Subject: [PATCH 2/3] Changes on RMRKTokenAttributes. No long uses structs as return values for batch getters. If a single attribute is sent on batch getter/setters it will use it for all collections and tokens. --- .../extension/tokenAttributes/IERC7508.sol | 40 +- .../RMRKTokenAttributesRepository.sol | 341 ++++++++++-------- .../extension/tokenAttributes/IERC7508.md | 92 ++--- .../RMRKTokenAttributesRepository.md | 114 +++--- test/extensions/tokenAttributesRepository.ts | 80 +--- test/interfaces.ts | 2 +- 6 files changed, 332 insertions(+), 337 deletions(-) diff --git a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol index c0aa8735..d709991b 100644 --- a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol +++ b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol @@ -748,11 +748,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 +766,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 ); /** @@ -783,13 +783,13 @@ interface IERC7508 is IERC165 { * @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 `StringAttribute` structs + * @return attributes An array of strings, in the same order as the attribute keys */ function getStringAttributes( address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) external view returns (StringAttribute[] memory attributes); + ) external view returns (string[] memory attributes); /** * @notice Used to get multiple uint parameter values for a token. @@ -801,13 +801,13 @@ interface IERC7508 is IERC165 { * @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 `UintAttribute` structs + * @return attributes An array of uints, in the same order as the attribute keys */ function getUintAttributes( address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) external view returns (UintAttribute[] memory attributes); + ) external view returns (uint256[] memory attributes); /** * @notice Used to get multiple bool parameter values for a token. @@ -819,13 +819,13 @@ interface IERC7508 is IERC165 { * @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 `BoolAttribute` structs + * @return attributes An array of bools, in the same order as the attribute keys */ function getBoolAttributes( address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) external view returns (BoolAttribute[] memory attributes); + ) external view returns (bool[] memory attributes); /** * @notice Used to get multiple address parameter values for a token. @@ -837,13 +837,13 @@ interface IERC7508 is IERC165 { * @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 `AddressAttribute` structs + * @return attributes An array of addresses, in the same order as the attribute keys */ function getAddressAttributes( address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) external view returns (AddressAttribute[] memory attributes); + ) external view returns (address[] memory attributes); /** * @notice Used to get multiple bytes parameter values for a token. @@ -855,11 +855,11 @@ interface IERC7508 is IERC165 { * @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 `BytesAttribute` structs + * @return attributes An array of bytes, in the same order as the attribute keys */ function getBytesAttributes( address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) external view returns (BytesAttribute[] memory attributes); + ) external view returns (bytes[] memory attributes); } diff --git a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol index bf647086..fe3d4ab5 100644 --- a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol +++ b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol @@ -366,11 +366,11 @@ 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 ) { address[] memory collections = new address[](1); @@ -400,24 +400,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) public view returns (StringAttribute[] memory attributes) { - uint256 length = attributeKeys.length; + ) public view returns (string[] memory attributes) { ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); - attributes = new StringAttribute[](length); + attributes = new string[](loopLength); - for (uint256 i; i < length; ) { - attributes[i] = StringAttribute({ - key: attributeKeys[i], - value: getStringAttribute( - multipleCollections ? collections[i] : collections[0], - multipleTokens ? tokenIds[i] : tokenIds[0], - attributeKeys[i] - ) - }); + 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; } @@ -431,24 +433,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) public view returns (UintAttribute[] memory attributes) { - uint256 length = attributeKeys.length; + ) public view returns (uint256[] memory attributes) { ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); - attributes = new UintAttribute[](length); + attributes = new uint256[](loopLength); - for (uint256 i; i < length; ) { - attributes[i] = UintAttribute({ - key: attributeKeys[i], - value: getUintAttribute( - multipleCollections ? collections[i] : collections[0], - multipleTokens ? tokenIds[i] : tokenIds[0], - attributeKeys[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; } @@ -462,24 +466,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) public view returns (BoolAttribute[] memory attributes) { - uint256 length = attributeKeys.length; + ) public view returns (bool[] memory attributes) { ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); - attributes = new BoolAttribute[](length); + attributes = new bool[](loopLength); - for (uint256 i; i < length; ) { - attributes[i] = BoolAttribute({ - key: attributeKeys[i], - value: getBoolAttribute( - multipleCollections ? collections[i] : collections[0], - multipleTokens ? tokenIds[i] : tokenIds[0], - attributeKeys[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; } @@ -493,24 +499,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) public view returns (AddressAttribute[] memory attributes) { - uint256 length = attributeKeys.length; + ) public view returns (address[] memory attributes) { ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); - attributes = new AddressAttribute[](length); + attributes = new address[](loopLength); - for (uint256 i; i < length; ) { - attributes[i] = AddressAttribute({ - key: attributeKeys[i], - value: getAddressAttribute( - multipleCollections ? collections[i] : collections[0], - multipleTokens ? tokenIds[i] : tokenIds[0], - attributeKeys[i] - ) - }); + 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; } @@ -524,24 +532,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address[] memory collections, uint256[] memory tokenIds, string[] memory attributeKeys - ) public view returns (BytesAttribute[] memory attributes) { - uint256 length = attributeKeys.length; + ) public view returns (bytes[] memory attributes) { ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); - attributes = new BytesAttribute[](length); + attributes = new bytes[](loopLength); - for (uint256 i; i < length; ) { - attributes[i] = BytesAttribute({ - key: attributeKeys[i], - value: getBytesAttribute( - multipleCollections ? collections[i] : collections[0], - multipleTokens ? tokenIds[i] : tokenIds[0], - attributeKeys[i] - ) - }); + 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; } @@ -731,22 +741,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { uint256[] memory tokenIds, BoolAttribute[] memory attributes ) external { - uint256 length = attributes.length; ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - for (uint256 i = 0; i < length; ) { - address collection = multipleCollections - ? collections[i] - : collections[0]; - uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + 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(), - collection, - tokenId, - attributes[i].key, - attributes[i].value + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -762,22 +776,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { uint256[] memory tokenIds, BytesAttribute[] memory attributes ) external { - uint256 length = attributes.length; ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - for (uint256 i = 0; i < length; ) { - address collection = multipleCollections - ? collections[i] - : collections[0]; - uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + 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(), - collection, - tokenId, - attributes[i].key, - attributes[i].value + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -793,22 +811,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { uint256[] memory tokenIds, StringAttribute[] memory attributes ) external { - uint256 length = attributes.length; ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - for (uint256 i = 0; i < length; ) { - address collection = multipleCollections - ? collections[i] - : collections[0]; - uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + 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(), - collection, - tokenId, - attributes[i].key, - attributes[i].value + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -824,22 +846,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { uint256[] memory tokenIds, UintAttribute[] memory attributes ) external { - uint256 length = attributes.length; ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - for (uint256 i = 0; i < length; ) { - address collection = multipleCollections - ? collections[i] - : collections[0]; - uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + 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(), - collection, - tokenId, - attributes[i].key, - attributes[i].value + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -855,22 +881,26 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { uint256[] memory tokenIds, AddressAttribute[] memory attributes ) external { - uint256 length = attributes.length; ( bool multipleCollections, - bool multipleTokens - ) = _checkIfMultipleCollectionsAndTokens(collections, tokenIds, length); - for (uint256 i = 0; i < length; ) { - address collection = multipleCollections - ? collections[i] - : collections[0]; - uint256 tokenId = multipleTokens ? tokenIds[i] : tokenIds[0]; + 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(), - collection, - tokenId, - attributes[i].key, - attributes[i].value + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value ); unchecked { ++i; @@ -891,7 +921,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { BytesAttribute[] memory bytesAttributes ) external { uint256 length = stringAttributes.length; - for (uint256 i = 0; i < length; ) { + for (uint256 i; i < length; ) { _setStringAttribute( _msgSender(), collection, @@ -905,7 +935,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = uintAttributes.length; - for (uint256 i = 0; i < length; ) { + for (uint256 i; i < length; ) { _setUintAttribute( _msgSender(), collection, @@ -919,7 +949,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = boolAttributes.length; - for (uint256 i = 0; i < length; ) { + for (uint256 i; i < length; ) { _setBoolAttribute( _msgSender(), collection, @@ -933,7 +963,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = addressAttributes.length; - for (uint256 i = 0; i < length; ) { + for (uint256 i; i < length; ) { _setAddressAttribute( _msgSender(), collection, @@ -947,7 +977,7 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } length = bytesAttributes.length; - for (uint256 i = 0; i < length; ) { + for (uint256 i; i < length; ) { _setBytesAttribute( _msgSender(), collection, @@ -965,15 +995,40 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { address[] memory collections, uint256[] memory tokenIds, uint256 attributesLength - ) internal pure returns (bool multipleCollections, bool multipleTokens) { + ) + internal + pure + returns ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) + { multipleCollections = collections.length != 1; multipleTokens = tokenIds.length != 1; + multipleAttributes = attributesLength != 1; if ( - (multipleCollections && collections.length != attributesLength) || - (multipleTokens && tokenIds.length != attributesLength) + (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( diff --git a/docs/RMRK/extension/tokenAttributes/IERC7508.md b/docs/RMRK/extension/tokenAttributes/IERC7508.md index 32f8100e..df3e0435 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,11 @@ 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 | ### getBoolAttribute @@ -117,7 +117,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 +128,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 +165,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 +176,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 +213,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 +224,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 +261,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 +272,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 +656,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 +667,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 @@ -715,7 +715,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 +726,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 +752,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 +763,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 +789,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 +800,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 +826,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 +837,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 diff --git a/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md b/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md index 2b05a4d1..884f3cac 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,11 @@ 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 | ### getBoolAttribute @@ -219,7 +219,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 +230,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 +267,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 +278,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 +315,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 +326,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 +363,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 +374,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 +758,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 +769,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 @@ -817,7 +817,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 +828,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 +854,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 +865,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 +891,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 +902,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 +928,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 +939,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 @@ -1135,17 +1135,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 +1168,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 76f89c74..53c7c4d9 100644 --- a/test/extensions/tokenAttributesRepository.ts +++ b/test/extensions/tokenAttributesRepository.ts @@ -437,26 +437,11 @@ 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'], ]); }); @@ -486,16 +471,7 @@ 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 () { @@ -524,16 +500,7 @@ 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 () { @@ -562,16 +529,7 @@ 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 () { @@ -600,16 +558,7 @@ 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 () { @@ -638,16 +587,7 @@ 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 () { diff --git a/test/interfaces.ts b/test/interfaces.ts index 1db845b6..dd0aaf6e 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 = '0x9f89917b'; // Attributes Repository export const IERC7590 = '0x6f87c75c'; // ERC20 Token Holder export const IOtherInterface = '0xffffffff'; export const IRMRKCatalog = '0xd912401f'; // ERC6220 From 97aedc7adb089ec824804c899160ef29faa0561d Mon Sep 17 00:00:00 2001 From: steven2308 Date: Tue, 5 Mar 2024 15:27:42 -0500 Subject: [PATCH 3/3] Adds methods to get and set attributes metadata for a collection. --- .../extension/tokenAttributes/IERC7508.sol | 30 ++++++++++ .../RMRKTokenAttributesRepository.sol | 41 +++++++++++--- .../extension/tokenAttributes/IERC7508.md | 56 +++++++++++++++++++ .../RMRKTokenAttributesRepository.md | 56 +++++++++++++++++++ test/interfaces.ts | 2 +- 5 files changed, 175 insertions(+), 10 deletions(-) diff --git a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol index d709991b..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. diff --git a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol index fe3d4ab5..f1711765 100644 --- a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol +++ b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol @@ -44,19 +44,22 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { "setAddressAttribute(address collection,uint256 tokenId,string memory key,address value)" ); - mapping(address collection => mapping(uint256 => AccessType)) + mapping(address collection => mapping(uint256 parameterId => AccessType accessType)) private _parameterAccessType; - mapping(address collection => mapping(uint256 => address)) + mapping(address collection => mapping(uint256 parameterId => address specificAddress)) private _parameterSpecificAddress; - mapping(address collection => IssuerSetting) private _issuerSettings; - mapping(address collection => mapping(address collaborator => bool)) + 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; + 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 collection => mapping(uint256 => mapping(uint256 => bytes))) @@ -177,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 */ @@ -1287,9 +1310,9 @@ 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]; } diff --git a/docs/RMRK/extension/tokenAttributes/IERC7508.md b/docs/RMRK/extension/tokenAttributes/IERC7508.md index df3e0435..28ee97a7 100644 --- a/docs/RMRK/extension/tokenAttributes/IERC7508.md +++ b/docs/RMRK/extension/tokenAttributes/IERC7508.md @@ -90,6 +90,28 @@ Used to retrieve multiple token attributes of any type at once. | 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 ```solidity @@ -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 @@ -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 884f3cac..352f69a3 100644 --- a/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md +++ b/docs/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.md @@ -192,6 +192,28 @@ Used to retrieve multiple token attributes of any type at once. | 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 ```solidity @@ -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 @@ -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 diff --git a/test/interfaces.ts b/test/interfaces.ts index dd0aaf6e..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 = '0x9f89917b'; // Attributes Repository +export const IERC7508 = '0x62ee8e7a'; // Attributes Repository export const IERC7590 = '0x6f87c75c'; // ERC20 Token Holder export const IOtherInterface = '0xffffffff'; export const IRMRKCatalog = '0xd912401f'; // ERC6220